분류 전체보기 1341

Ch06. 동기화 - 출금

멀티스레드를 사용할 때 가장 주의해야 할 점은, 같은 자원(리소스)에 여러 스레드가 동시에 접근할 때 발생하는 동시성 문제이다. 참고로 여러 스레드가 접근하는 자원을 공유 자원이라 한다. 대표적인 공유 자원은 인스턴스의 필드(멤버 변 수)이다.멀티스레드를 사용할 때는 이런 공유 자원에 대한 접근을 적절하게 동기화(synchronization)해서 동시성 문제가 발생 하지 않게 방지하는 것이 중요하다.출금 예제BankAccount(인터페이스)BankAccount 인터페이스이다. 앞으로 이 인터페이스의 구현체를 점진적으로 발전시키면서 문제를 해결할 예정이다.withdraw(amount) : 계좌의 돈을 출금한다. 출금할 금액을 매개변수로 받는다.계좌의 잔액이 출금할 금액보다 많다면 출금에 성공하고, true..

Ch06. 동기화 - synchronized

BankAccountV1와 같은데, withdraw() , getBalance() 코드에 synchronized 키워드가 추가되었다.이제 withdraw() , getBalance() 메서드는 한 번에 하나의 스레드만 실행할 수 있다.실행 결과를 보면 "t1"이 withdraw() 메서드를 시작부터 완료까지 모두 끝내고 나서, 그 다음에 "t2"가 withdraw() 메서드를 수행하는 것을 확인할 수 있다. 물론 환경에 따라 "t2"가 먼저 실행될 수도 있다. 이 경우에도 "t2"가 withdraw() 메서드를 모두 수행한 다음에 "t1"이 withdraw() 메서드를 수행한다.Synchronized 분석모든 객체(인스턴스)는 내부에 자신만의 락( lock )을 가지고 있다.모니터 락(monitor lo..

Ch06. 동기화 - 임계 영역

이런 문제가 발생한 근본 원인은 여러 스레드가 함께 사용하는 공유 자원을 여러 단계로 나누어 사용하기 때문이다.검증 단계: 잔액( balance )이 출금액( amount ) 보다 많은지 확인한다.출금 단계: 잔액( balance )을 출금액( amount ) 만큼 줄인다.출금() { //검증 단계: 잔액(balance) 확인 //출금 단계: 잔액(balance) 감소}이 로직에는 하나의 큰 가정이 있다.스레드 하나의관점에서 출금()을보면검증 단계에서 확인한 잔액( balance ) 1000원은 출금 단계에서 계산을 끝마칠 때까지 같은 1000원으로 유지되어야 한다. 그래야 검증 단계에서 확인한 금액으로, 출금 단계에서 정확한 잔액을 계산할 수 있다.그래야 검증 단계에서 확인한 1000원에 800원을 ..

Ch06. 동기화 - 동시성 문제

멀티스레드를 사용할 때 가장 주의해야 할 점은, 같은 자원(리소스)에 여러 스레드가 동시에 접근할 때 발생하는 동시성 문제이다. 참고로 여러 스레드가 접근하는 자원을 공유 자원이라 한다. 대표적인 공유 자원은 인스턴스의 필드(멤버 변 수)이다.멀티스레드를 사용할 때는 이런 공유 자원에 대한 접근을 적절하게 동기화(synchronization)해서 동시성문제가 발생하지 않게 방지하는 것이 중요하다.출금 예제BankAccount(인터페이스)BankAccount 인터페이스이다. 앞으로 이 인터페이스의 구현체를 점진적으로 발전시키면서 문제를 해결할 예정이다.withdraw(amount) : 계좌의 돈을 출금한다. 출금할 금액을 매개변수로 받는다.계좌의 잔액이 출금할 금액보다 많다면 출금에 성공하고, true를 ..

Ch05. 메모리 가시성 - 자바 메모리 모델

메모리 가시성(memory visibility)멀티스레드 환경에서 한 스레드가 변경한 값이 다른 스레드에서 언제 보이는지에 대한 것을 메모리 가시성(memory visibility)이라 한다. 이름 그대로 메모리에 변경한 값이 보이는가, 보이지 않는가의 문제이다.Java Memory ModelJava Memory Model(JMM)은 자바 프로그램이 어떻게 메모리에 접근하고 수정할 수 있는지를 규정하며, 특히 멀티 스레드 프로그래밍에서 스레드 간의 상호작용을 정의한다. JMM에 여러 가지 내용이 있지만, 핵심은 여러 스레드들의 작업 순서를 보장하는 happens-before 관계에 대한 정의다.happens-beforehappens-before 관계는 자바 메모리 모델에서 스레드 간의 작업 순서를 정의하..

Ch05. 메모리 가시성 - volatile 예시

Volatile 미적용work 스레드work 스레드는 반복문에서 count++ 을 사용해서 이 값을 계속 증가한다.반복문을 1억 번 실행할 때마다 한 번씩 count의 값을 출력한다.flag 값이 false 가 되면 반복문을 탈출하고 count 값을 출력한다.main 스레드"main" 스레드는 1초간 대기하다가 flag 값을 false로 변경한다.flag 값을 false로 변경한 시점에 count 값을 출력한다main 스레드가 flag 를 false로 변경한 시점에 count 값은 555996592이다.work 스레드가 이후에 flag 를 확인하지만 아직 flag = true이다.work 스레드가 사용하는 캐시 메모리에서 읽은 것이다.work 스레드는 반복문을 계속 실행하면서 count 값을 증가시킨다...

Ch05. 메모리 가시성 - volatile, 메모리 가시성

VolatileV1프로그램은 아주 간단하다. runFlag를 사용해서 스레드의 작업을 종료한다.예상 시나리오"work"스레드는 MyTask를 실행한다. 여기에는 runFlag를 체크하는 무한 루프가 있다.runFlag 값이 false 가 되면 무한 루프를 탈출하며 작업을 종료한다.이후에 "main "스레드가 runFlag의 값을 false로 변경한다.runFlag의 값이 false 가 되었으므로 "work" 스레드는 무한 루프를 탈출하며, 작업을 종료한다.실제 실행 결과를 보면 task 종료가 출력되지 않는다! 그리고 자바 프로그램도 멈추지 않고 계속 실행된다. 정확히는 work 스레드가 while문에서 빠져나오지 못하고 있는 것이다."main" 스레드, "work" 스레드 모두 MyTask 인스턴스( ..

Ch04. 스레드 제어와 생명 주기2 - yield

어떤 스레드를 얼마나 실행할지는 운영체제가 스케줄링을 통해 결정한다. 그런데 특정 스레드가 크게 바쁘지 않은 상황 이어서 다른 스레드에 CPU 실행 기회를 양보하고 싶을 수 있다. 이렇게 양보하면 스케줄링 큐에 대기 중인 다른 스레드 가 CPU 실행 기회를 더 빨리 얻을 수 있다.Empty(아무것도 적용 X)1000개의 스레드를 실행한다.각 스레드가 실행하는 로직은 아주 단순하다. 스레드당 0~9까지 출력하면 끝난다.sleep(1) , yield() 없이 호출한다. 운영체제의 스레드 스케줄링을 따른다. 특정 스레드가 쭉~ 수행된 다음에 다른 스레드가 수행되는 것을 확인할 수 있다.참고로 실행 환경에 따라 결과는 달라질 수 있다. 다른 예시보다 상대적으로 하나의 스레드가 쭉~ 연달아 실행되 다가 다른 스레..

Ch04. 스레드 제어와 생명 주기2 - 프린트 예제

프린트 예제 V1volatile : 여러 스레드가 동시에 접근하는 변수에는 "volatile" 키워드를 붙어주어야 안전하다. 여기서는 "main" 스레드, printer 스레드 둘 다 "work" 변수에 동시에 접근할 수 있다. ConcurrentLinkedQueue : 여러 스레드가 동시에 접근하는 경우, 컬렉션 프레임워크가 제공하는 일반적인 자료구조를 사용하면 안전하지 않다. 여러 스레드가 동시에 접근하는 경우 동시성을 지원하는 동시성 컬렉션을 사용해야 한다. Queue의 경우 ConcurrentLinkedQueue를 사용하면 된다. 프린트 동작 과정main 스레드: 사용자의 입력을 받아서 Printer 인스턴스의 jobQueue에 담는다.printer 스레드: jobQueue 가 있는지 확인한다.j..

Ch04. 스레드 제어와 생명 주기2 - 인터럽트

특정 스레드를 작업 중간에 중단하기특정 스레드의 작업을 중단하는 가장 쉬운 방법은 변수를 사용하는 것이다.여기서는 runFlag 를 사용해서 "work"스레드에 작업 중단을 지시할 수 있다.작업 하나에 3초가 걸린다고 가정하고, sleep(3000)을 사용하자."main" 스레드는 4초 뒤에 작업 중단을 지시한다."volatile" 키워드는 단순히 여러 스레드에서 공유하는 값에 사용하는 키워드 라고 알아두자."work" 스레드는 runFlag가 true인 동안 계속 실행된다.프로그램 시작 후 4초 뒤에 "main" 스레드는 runFlag를 false로 변경한다."work" 스레드는 while(runFlag) 코드에서 runFlag의 조건이 false로 변한 것을 확인하고, while문을 빠져나가면서 작업..