Java 병렬 프로그래밍에서 사용자 정의 동기화 도구 구축

Java 라이브러리에 적합한 동기화 도구가 제공되지 않으면 사용자 정의 동기화 도구를 구축해야 합니다.
차단 가능 상태가 조작에 의존하는 구조

acquir lock on object state;//
while(precondition does not hold){//
   release lock;//
   wait until precondition might hold;//
   optionlly fail if interrupted or timeout expires;//
   reacquire lock;//
}
perform action//
   release lock;//
유계 캐시 구현 기본 클래스 예시

public class BaseBoundBuffer<V> {
private final V[] buf;
private int tail;
private int head;
private int count;
@SuppressWarnings("unchecked")
public BaseBoundBuffer(int capacity) {
buf = (V[]) new Object[capacity];
}
public synchronized void doPut(V v) {
buf[tail] = v;
if (++tail == buf.length)
tail = 0;
count++;
}
public synchronized V doTake() {
V v = buf[head];

if (++head == buf.length)
head = 0;
count--;
return v;
}
public final synchronized boolean isFull() {
return count == buf.length;
}
public final synchronized boolean isEmpty() {
return count == 0;
}
}

차단 실현 방식 1: 호출자에게 이상 던지기

public synchronized void put1(V v)  throws Exception{
if(isFull())
throw new Exception("full error");
doPut(v);
}
분석: 이상은 이상 발생 상황에 응용해야 하는데 여기서 이상을 던지는 것은 적합하지 않다.호출자가 필요한 것은 전제조건을 처리하는 데 실패한 상황이며 근본적인 문제를 해결하지 못했다.
차단 실현 방식 2: 윤문과 휴면을 통해

public void put2(V v) throws InterruptedException {
while (true) {//
synchronized (this) {
if (!isFull()) {
doPut(v);
return;    
}
}
Thread.sleep(SLEEP_TIME);//
}
}
분석: 휴면 시간 측정 어려움 SLEEP_TIME 설정.너무 작게 설정하면 CPU가 여러 번 폴링되고 CPU 자원이 많이 소모될 수 있습니다.설정이 너무 크면 응답성이 낮아집니다.
저지 실현 방식 3: 조건 대기열
조건 대기열의 요소는 관련 조건을 기다리는 라인입니다.모든 자바 대상은 하나의 자물쇠로 사용할 수 있고 모든 대상은 하나의 조건 대기열로 할 수 있으며 Object의wait,notify,notifyAll 방법은 내부 조건 대기열의 API를 구성한다.Object.wait는 자동으로 자물쇠를 풀고 운영체제에 현재 라인을 걸어 다른 라인이 자물쇠를 얻고 대상의 상태를 수정할 수 있도록 요청합니다.Object.notify 및 Object.notifyAll은 대기 중인 스레드를 깨울 수 있습니다. 조건 대기열에서 스레드 깨우기를 선택하고 자물쇠를 다시 가져옵니다.

public synchronized void put3(V v) throws InterruptedException {
while(isFull())
wait();
doput(v);
notifyAll();
}
분석: 비교적 좋은 응답을 얻고 간단하고 사용하기 쉽다.
조건 대기열 사용
1. 조건술어
1).정의: 조건 술어는 어떤 조작을 상태 의존 조작으로 만드는 전제 조건이다.조건 술어는 클래스의 각 상태 변수로 구성된 표현식이다.예를 들어put방법의 조건술어는'캐시가 비어 있지 않다'는 것이다.
2).관계: 조건 대기에서 중요한 삼원 관계가 존재하는데 자물쇠,wait 방법과 조건 술어를 포함한다.조건 술어에는 여러 개의 상태 변수가 포함되어 있으며, 모든 상태 변수는 하나의 자물쇠로 보호되어야 하기 때문에 조건 술어를 테스트하기 전에 반드시 이 자물쇠를 소지해야 한다.잠금 대상과 조건 대기열 대상 (와wait와notify 등 방법이 있는 대상) 은 같은 대상이어야 합니다.
3).제약: 매번wait를 호출할 때마다 특정한 조건 술어와 은밀하게 관련된다. 특정한 조건 술어를 호출할 때 호출자는 반드시 조건 대기열과 관련된 자물쇠를 가지고 있어야 한다. 이 자물쇠는 이 구성 조건 술어의 상태 변수를 보호해야 한다.
2. 조건 대기열 사용 규칙
1).보통 조건 술어가 하나 있다
2).영원히 웨이트를 호출하기 전에 조건 술어를 테스트하고wait에서 되돌아온 후에 다시 테스트합니다.
3).영원히 순환 중wait 호출;
4).조건 술어를 구성하는 상태 변수가 잠겨 보호되고 이 잠금은 이 조건 대기열과 연결되어야 한다.
5).wait, notify, notifyAll을 호출할 때 조건 대기열과 관련된 자물쇠를 소지해야 합니다.
6).조건 술어를 검사한 후 보호된 논리를 실행하기 전에 자물쇠를 놓지 마십시오.
3. 통지
nofify가 아닌 notifyAll을 사용하십시오.nofify는 랜덤으로 하나의 라인을 깨워서 휴면 상태에서 Blocked 상태로 바꿉니다. (Blocked 상태는 자물쇠를 가져오려고 시도하는 상태입니다. 즉, 자물쇠가 사용할 수 있는 것을 발견하면 바로 자물쇠를 가지고 있습니다.) notifyAll은 조건 대기열의 모든 라인을 휴면 상태에서 Blocked 상태로 바꿉니다.이런 상황을 고려하면 만약에 스레드 A가 조건 서술어 Pa 때문에 휴면 상태에 들어가면 스레드 B는 조건 서술어 Pb 때문에 휴면 상태에 들어간다.이때 Pb는 진실이고 스레드 C는 단일한 notify를 실행합니다.만약 JVM이 랜덤으로 스레드 A를 선택하여 깨우면, 스레드 A 검사 조건 술어 Pa가 사실이 아닌 후에 휴면 상태에 들어갑니다.이 이후로 더 이상 다른 라인이 깨어나지 않으면 프로그램은 계속 휴면 상태에 있을 것이다.notifyAll을 사용하면 JVM은 조건 대기열에 있는 모든 대기 스레드가 휴면 상태에서 Blocked 상태로 바뀌는 것을 깨우쳐 줍니다. 무작위로 하나의 스레드를 선택하더라도 조건 술어가 진실이 아니라 휴면 상태로 들어가기 때문에 다른 스레드는 경쟁 잠금 상태로 내려가게 됩니다.
4. 상태 의존 방법의 표준 형식

void stateDependentMethod throwsInterruptedException{
synchronized(lock){
while(!conditionPredicate))
lock.wait();
}
//dosomething();
....

notifyAll();
}

Condition 객체 표시
표시된 Condition 대상은 더욱 유연한 선택으로 더욱 풍부한 기능을 제공한다. 모든 자물쇠에 여러 개의 대기가 존재할 수 있고, 조건 대기는 중단할 수 없는 대기, 시한을 바탕으로 하는 대기, 그리고 공평하거나 비공평한 대기열 조작이 있을 수 있다.하나의 Condition은 하나의 Lock과 연결될 수 있습니다. 마치 하나의 조건 대기열과 하나의 내장 자물쇠와 연결됩니다.Condition을 만들려면 관련 Lock에서 Lock을 호출합니다.newCondition 메서드.다음은 디스플레이 조건 변수로 유계 캐시를 다시 실현합니다

public class ConditionBoundedBuffer<V> {
 private final V[] buf;
 private int tail;
 private int head;
 private int count;
 private Lock lock = new ReentrantLock();
 private Condition notFullCondition = lock.newCondition();
 private Condition notEmptyCondition = lock.newCondition();
 @SuppressWarnings("unchecked")
 public ConditionBoundedBuffer(int capacity) {
  buf = (V[]) new Object[capacity];
 }

 public void doPut(V v) throws InterruptedException {
  try {
   lock.lock();
   while (count == buf.length)
    notFullCondition.await();
   buf[tail] = v;
   if (++tail == buf.length)
    tail = 0;
   count++;
   notEmptyCondition.signal();
  } finally {
   lock.unlock();
  }

 }

 public V doTake() throws InterruptedException {
  try {
   lock.lock();
   while (count == 0)
    notEmptyCondition.await();
   V v = buf[head];
   buf[head] = null;
   if (++head == buf.length)
    head = 0;
   count--;
   notFullCondition.signal();
   return v;
  } finally {
   lock.unlock();
  }
 }
}

좋은 웹페이지 즐겨찾기