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

6051 단어
자바 라이브러리에서 적합한 동기화 도구를 제공하지 않을 때 사용자 정의 동기화 도구를 구축해야 합니다.
차단 가능 상태 조작에 의존하는 구조
 
  
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 {
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);//
}
}

분석: 절전 모드 SLEEPTIME 설정너무 작게 설정하면 CPU가 여러 번 폴링되고 CPU 자원이 많이 소모될 수 있습니다.설정이 너무 크면 응답성이 낮아집니다.
차단 실현 방식 3: 조건 대기열
조건 대기열의 요소는 관련 조건을 기다리는 라인입니다.모든 자바 대상은 하나의 자물쇠가 될 수 있고, 모든 대상은 하나의 조건 대기열이 될 수 있으며, Object의wait, notify, notify All 방법은 내부 조건 대기열의 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가 있다.영원히 웨이트를 호출하기 전에 조건 술어를 테스트하고 웨이트에서 되돌아온 후에 다시 테스트한다.3).영원히 순환 중wait 호출하기;4).조건 술어를 구성하는 상태 변수가 잠겨 보호되고 이 잠금은 반드시 이 조건 대기열과 연결되어야 한다.5).wait, notify, notify All을 호출할 때 조건 대기열과 연결된 자물쇠를 가지고 있어야 합니다.6).조건 술어를 검사한 후 보호된 논리를 실행하기 전에 자물쇠를 풀지 마십시오.
3. 통지
가능한 한 notify All을 사용하십시오. nofify가 아니라.nofify는 랜덤으로 한 라인을 깨우기 때문에 휴면 상태에서 Blocked 상태로 바꿉니다. (Blocked 상태는 자물쇠를 가져오려고 시도하는 상태입니다. 즉, 자물쇠가 사용 가능한 것을 발견하면 바로 자물쇠를 가지고 있습니다.) notify All은 조건 대기열의 모든 라인을 깨우고 휴면 상태에서 Blocked 상태로 바꿉니다.이런 상황을 고려하면 만약에 스레드 A가 조건술어 Pa로 인해 휴면 상태에 들어가고 스레드 B는 조건술어 Pb로 인해 휴면 상태에 들어간다.이 때 Pb는 진짜이고, 스레드 C는 단일한 notify를 실행합니다.만약 JVM이 랜덤으로 스레드 A를 선택하여 깨우면 스레드 A 검사 조건의 술어인 Pa는 진실이 되지 않고 다시 휴면 상태에 들어간다.그 이후로 다시는 다른 라인이 깨어나지 않고 프로그램은 계속 휴면 상태에 있을 것이다.notify All을 사용하면 달라집니다. JVM은 조건 대기열의 모든 대기 라인을 휴면 상태에서 Blocked 상태로 깨웁니다. 조건 술어가 휴면 상태에 들어가지 않아도 다른 라인은 경쟁 자물쇠를 제거하고 계속 실행합니다.
4. 상태 의존 방법의 표준 형식
 
  
void stateDependentMethod throwsInterruptedException{
synchronized(lock){
while(!conditionPredicate))
lock.wait();
}
//dosomething();
....

notifyAll();
}


Condition 객체 표시
표시된 Condition 객체는 보다 유연한 선택이며 다양한 기능을 제공합니다. 각 잠금장치에 여러 개의 대기 시간이 존재할 수 있고 조건 대기 시간은 중단할 수 없는 대기 시간, 시한에 기초한 대기 시간, 공평하거나 비공평한 대기열 조작을 할 수 있습니다.하나의 Condition은 하나의 Lock과 연결될 수 있으며, 마치 하나의 조건 대기열과 하나의 내장 자물쇠와 연결될 수 있다.Condition을 만들려면 연관된 Lock에서 Lock을 호출합니다.new Condition 메서드.다음은 디스플레이 조건 변수로 경계 캐시를 다시 실현합니다
 
  
public class ConditionBoundedBuffer {
 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();
  }
 }
}

좋은 웹페이지 즐겨찾기