분류 전체보기 1341

Ch09. 생산자 소비자 문제 - Lock Condition

생산자가 생산자를 깨우고, 소비자가 소비자를 깨우는 비효율 문제를 어떻게 해결할 수 있을까?해결 방안: 핵심은 생산자 스레드는 데이터를 생성하고, 대기 중인 소비자 스레드에게 알려주어야 한다. 반대로 소비자 스레드는 데이터를 소비하고, 대기 중인 생산자 스레드에게 알려주면 된다. 결국 생산자 스레드가 대기하는 대기 집합과, 소비자 스레드가 대기하는 대기 집합을 둘로 나누면 된다. 그리고 생산자 스레드가 데이터를 생산하면 소비자 스레드가 대기하는 대기 집합에만 알려주고, 소비자 스레드가 데이터를 소비하면 생산자 스레드가 대기하는 대기 집합에만 열려주면 되는 것이다. 이렇게 생산자용, 소비자용 대기 집합을 서로 나누어 분리하면 비효율 문제를 깔끔하게 해결할 수 있다. 그럼 대기 집합을 어떻게 분리할 수 있을..

Ch08. 생산자 소비자 문제 - wait, notify의 한계

지금까지 살펴본 Object.wait() , Object.notify() 방식은 스레드 대기 집합 하나에 생산자, 소비자 스레드를 모두 관리한다.그리고 notify() 를 호출할 때 임의의 스레드가 선택된다. 따라서 앞서 살펴본 것 처럼 큐에 데이터가 없는 상황에 소비자가 같은 소비자를 깨우는 비효율이 발생할 수 있다. 또는 큐에 데이터가 가득 차있는데 생산자가 같 은 생산자를 깨우는 비효율도 발생할 수 있다. 비효율 생산자 실행다음과 같은 상황을 가정하겠다.큐에 "dataX"가 보관되어 있다.스레드 대기 집합에는 다음 스레드가 대기하고 있다.소비자: c1 , c2 , c3생산자: p1 , p2 , p3p0 스레드가 data0 생산을 시도한다.p0 스레드가 실행되면서 data0를 큐에 저장한다. 이때 큐..

Ch08. 생산자 소비자 문제 - 예제3(wait, notify)

앞서 설명한 synchronized를 사용한 임계 영역 안에서 락을 가지고 무한 대기하는 문제는 흥미롭게도 Object 클 래스에 해결 방안이 있다. Object 클래스는 이런 문제를 해결할 수 있는 wait() , notify()라는 메서드를 제공한다. Object는 모든 자바 객체의 부모이기 때문에, 여기 있는 기능들은 모두 자바 언어의 기본 기능이라 생각하면 된다. wait(), notify() 설명 Object.wait()현재 스레드가 가진 락을 반납하고 대기("WAITING")한다.현재 스레드를 대기("WAITING") 상태로 전환한다. 이 메서드는 현재 스레드가 synchronized 블록이나 메서드에서 락을 소유하고 있을 때만 호출할 수 있다. 호출한 스레드는 락을 반납하고, 다른 스레드가 ..

Ch08. 생산자 소비자 문제 - 예제2(생산자, 소비자 대기)

put(data): 데이터를 버리지 않는 대안data3을 버리지 않는 대안은, 큐가 가득 찾을 때, 큐에 빈 공간이 생길 때까지, 생산자 스레드가 기다리면 된다. 언젠가는 소비자 스레드가 실행되어서 큐의 데이터를 가져갈 것이고, 그러면 큐에 데이터를 넣을 수 있는 공간이 생기게 된다.여기서는 생산자 스레드가 반복문을 사용해서 큐에 빈 공간이 생기는지 주기적으로 체크한다. 만약 빈 공간이 없다면 sleep()을 사용해서 잠시 대기하고, 깨어난 다음에 다시 반복문에서 큐의 빈 공간을 체크하는 식으로 구현했다.take(): 큐에 데이터가 없다면 기다리자소비자 입장에서 큐에 데이터가 없다면 기다리는 것도 대안이다. 큐에 데이터가 없을 때 null을 받지 않는 대안은, 큐에 데이터가 추가될 때까지 소비자 스레드가..

Ch08. 생산자 소비자 문제 - 예제1(생산자, 소비자 우선)

실행 코드BoundedQueue: 버퍼 역할을 하는 큐의 인터페이스이다.put(data): 버퍼에 데이터를 보관한다. (생산자 스레드가 호출하고, 데이터를 생산한다.)take(): 버퍼에 보관된 값을 가져간다. (소비자 스레드가 호출하고, 데이터를 소비한다.)BoundedQueueV1 : 한정된 버퍼 역할을 하는 가장 단순한 구현체이다. 이후에 버전이 점점 올라가면서 코드를 개선한다.Queue , ArrayDeque : 데이터를 중간에 보관하는 버퍼로 큐( Queue )를 사용한다. 구현체로는 ArrayDeque를 사용한다.int max : 한정된(Bounded) 버퍼이므로, 버퍼에 저장할 수 있는 최대 크기를 지정한다.put() : 큐에 데이터를 저장한다. 큐가 가득 찬 경우 더는 데이터를 보관할 수 ..

Ch08. 생산자 소비자 문제 - 소개

생산자 소비자 문제는 멀티스레드 프로그래밍에서 자주 등장하는 동시성 문제 중 하나로, 여러 스레드가 동시에 데이터를 생산하고 소비하는 상황을 다룬다.멀티스레드의 핵심을 제대로 이해하려면 반드시 생산자 소비자 문제를 이해하고, 올바른 해결 방안도 함께 알아두어야 한다.생산자 소비자 문제를 제대로 이해하면 멀티스레드를 제대로 이해했다고 볼 수 있다. 그만큼 중요한 내용이다.생산자 - 소비자 문제 예시생산자(Producer): 데이터를 생성하는 역할을 한다. 예를 들어, 파일에서 데이터를 읽어오거나 네트워크에서 데 이터를 받아오는 스레드가 생산자 역할을 할 수 있다.앞서 프린터 예제에서 사용자의 입력을 프린터 큐에 전달하는 스레드가 생산자의 역할이다.소비자(Consumer): 생성된 데이터를 사용하는 역할을 ..

Ch07. 고급 동기화(concurrent.Lock) - ReentrantLock

자바는 1.0부터 존재한 synchronized와 "BLOCKED" 상태를 통한 통한 임계 영역 관리의 한계를 극복하기 위해 자바 1.5부터 Lock 인터페이스와 ReentrantLock 구현체를 제공한다.synchronized 단점무한 대기: "BLOCKED" 상태의 스레드는 락이 풀릴 때까지 무한 대기한다.특정 시간까지만 대기하는 타임아웃 X중간에 인터럽트 X공정성: 락이 돌아왔을 때 "BLOCKED" 상태의 여러 스레드 중에 어떤 스레드가 락을 획득할지 알 수 없다. 최악의 경우 특정 스레드가 너무 오랜 기간 락을 획득하지 못할 수 있다.public interface Lock { /** * Acquires the lock. * * If the lock is not avai..

Ch07. 고급 동기화(concurrent.Lock) - LockSupport

"synchronized"는 자바 1.0부터 제공되는 매우 편리한 기능이지만, 다음과 같은 한계가 있다.synchronized 단점무한 대기: "BLOCKED" 상태의 스레드는 락이 풀릴 때까지 무한 대기한다.특정 시간까지만 대기하는 타임아웃 X중간에 인터럽트 X공정성: 락이 돌아왔을 때 "BLOCKED" 상태의 여러 스레드 중에 어떤 스레드가 락을 획득할지 알 수 없다. 최악의 경우 특정 스레드가 너무 오랜 기간 락을 획득하지 못할 수 있다.결국 더 유연하고, 더 세밀한 제어가 가능한 방법들이 필요하게 되었다. 이런 문제를 해결하기 위해 자바 1.5부터 java.util.concurrent라는 동시성 문제 해결을 위한 라이브러리 패키지가 추가된다. 이 라이브러리에는 수많은 클래스가 있지만, 가장 기본이..

Ch06. 동기화 - Synchronized 정리

자바는 처음부터 멀티스레드를 고려하고 나온 언어이다. 그래서 자바 1.0부터 synchronized 같은 동기화 방법을 프로그래밍 언어의 문법에 포함해서 제공한다.synchronized 장점프로그래밍 언어에 문법으로 제공아주 편리한 사용자동 잠금 해제: synchronized 메서드나 블록이 완료되면 자동으로 락을 대기 중인 다른 스레드의 잠금이 해제된다. 개발자가 직접 특정 스레드를 깨우도록 관리해야 한다면, 매우 어렵고 번거로울 것이다.synchronized는 매우 편리하지만, 제공하는 기능이 너무 단순하다는 단점이 있다. 시간이 점점 지나면서 멀티스레드가 더 중요해지고 점점 더 복잡한 동시성 개발 방법들이 필요해졌다.synchronized 단점무한 대기: "BLOCKED" 상태의 스레드는 락이 풀릴..

Ch06. 동기화 - 문제와 풀이

문제 1 - 공유 자원다음 코드의 결과는 20000이 되어야 한다. 이 코드의 문제점을 찾아서 해결해라. 이 코드에서 다른 부분은 변경하면 안 되고,`Counter` 클래스 내부만 수정해야 한다. 정답 코드count는 여러 스레드가 함께 사용하는 공유 자원이다.단일 스레드가 공유 자원에 접근하는 상황count 값이 0이라고 가정하겠다.count의 값을 읽는다. count 값은 0이다.읽은 count의 값에 1을 더한다. 0+1=1이다.더한 결과를count에 다시 저장한다. count 값은 1이다.이처럼 단일 스레드가 공유 자원에 접근하는 경우는 아무런 문제가 없다. 여러 스레드가 공유 자원에 함께 접근하는 상황count 값이 0이라고 가정하겠다. 2개의 스레드가 동시에 increment() 메서드를 호출..