Java concurrency 의 Condition 조건동력 노드 자바 대학 정리

9983 단어
조건 소개
Condition 의 역할 은 자 물 쇠 를 더욱 정확하게 제어 하 는 것 이다.Condition 의 await () 방법 은 Object 의 wait () 방법, Condition 의 signal () 방법 은 Object 의 notify () 방법, Condition 의 signal All () 은 Object 의 notify All () 방법 에 해당 합 니 다.다른 것 은 Object 의 wait (), notify (), notify All () 방법 은 '동기 화 잠 금' (synchronized 키워드) 과 묶 어서 사용 합 니 다.반면 Condition 은 '상호 배척 자물쇠'/'공유 자물쇠' 와 묶 어 사용 해 야 한다.
Condition 함수 목록

//                          。
void await()
//            、                      。
boolean await(long time, TimeUnit unit)
//            、                      。
long awaitNanos(long nanosTimeout)
//                      。
void awaitUninterruptibly()
//            、                      。
boolean awaitUntil(Date deadline)
//         。
void signal()
//         。
void signalAll()

Condition 예제
예제 1 은 Object 의 wait (), notify () 를 통 해 스 레 드 의 휴면/깨 우기 기능 을 보 여 줍 니 다.
예제 2 는 Condition 의 await (), signal () 을 통 해 스 레 드 의 휴면/깨 우기 기능 을 보 여 줍 니 다.
예시 3 은 Condition 을 통과 하 는 고급 기능 이다.
예시 1

public class WaitTest1 {
  public static void main(String[] args) {
    ThreadA ta = new ThreadA("ta");
    synchronized(ta) { //   synchronized(ta)  “  ta    ”
      try {
        System.out.println(Thread.currentThread().getName()+" start ta");
        ta.start();
        System.out.println(Thread.currentThread().getName()+" block");
        ta.wait();  //   
        System.out.println(Thread.currentThread().getName()+" continue");
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }
  }
  static class ThreadA extends Thread{
    public ThreadA(String name) {
      super(name);
    }
    public void run() {
      synchronized (this) { //   synchronized(this)  “        ”
        System.out.println(Thread.currentThread().getName()+" wakup others");
        notify();  //   “          ”
      }
    }
  }
}

예시 2

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
public class ConditionTest1 {
  private static Lock lock = new ReentrantLock();
  private static Condition condition = lock.newCondition();
  public static void main(String[] args) {
    ThreadA ta = new ThreadA("ta");
    lock.lock(); //    
    try {
      System.out.println(Thread.currentThread().getName()+" start ta");
      ta.start();
      System.out.println(Thread.currentThread().getName()+" block");
      condition.await();  //   
      System.out.println(Thread.currentThread().getName()+" continue");
    } catch (InterruptedException e) {
      e.printStackTrace();
    } finally {
      lock.unlock();  //    
    }
  }
  static class ThreadA extends Thread{
    public ThreadA(String name) {
      super(name);
    }
    public void run() {
      lock.lock();  //    
      try {
        System.out.println(Thread.currentThread().getName()+" wakup others");
        condition.signal();  //   “condition         ”
      } finally {
        lock.unlock();  //    
      }
    }
  }
}

실행 결과:

main start ta
main block
ta wakup others
main continue

"예제 1"과 "예제 2"를 통 해 Condition 과 Object 의 방법 이 대응 하 는 관 계 를 가 진 다 는 것 을 알 수 있 습 니 다.
              Object      Condition  휴면          wait        await 스 레 드 깨 우기     notify      signal 모든 스 레 드 깨 우기   notifyAll   signalAll
Condition 은 위의 기능 을 지원 하 는 것 외 에 더 강 한 점 은 다 중 스 레 드 의 휴면 과 각성 을 더욱 정교 하 게 제어 할 수 있다 는 것 이다.같은 자물쇠 에 대해 서 는 여러 개의 Condition 을 만 들 고 서로 다른 상황 에서 서로 다른 Condition 을 사용 할 수 있 습 니 다.
예 를 들 어 다 중 스 레 드 가 같은 버퍼 를 읽 거나 쓰 면 버퍼 에 데 이 터 를 기록 한 후에 '읽 기 스 레 드' 를 깨 웁 니 다.버퍼 에서 데 이 터 를 읽 은 후에 '쓰기 스 레 드' 를 깨 웁 니 다.또한 버퍼 가 가득 찼 을 때 '스 레 드 쓰기' 는 기 다 려 야 합 니 다.버퍼 가 비어 있 을 때 '읽 기 스 레 드' 는 기 다 려 야 합 니 다.        Object 클래스 의 wait (), notify (), notify All () 을 사용 하면 버퍼 에 데 이 터 를 기록 한 후 '읽 기 스 레 드' 를 깨 워 야 할 때 notify () 나 notify All () 을 통 해 '읽 기 스 레 드' 를 명확 하 게 지정 할 수 없고 notify All 을 통 해 모든 스 레 드 를 깨 울 수 있 습 니 다 (단, notify All 은 깨 운 스 레 드 가 읽 기 스 레 드 인지 쓰기 스 레 드 인지 구분 할 수 없습니다). 단, Condition 을 통 해 읽 기 스 레 드 를 명확 하 게 지정 할 수 있 습 니 다.
아래 의 예 3 을 보면 이 개념 에 대해 더욱 깊이 이해 할 수 있 을 것 이다. 
예시 3

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
class BoundedBuffer {
  final Lock lock = new ReentrantLock();
  final Condition notFull = lock.newCondition(); 
  final Condition notEmpty = lock.newCondition(); 
  final Object[] items = new Object[5];
  int putptr, takeptr, count;
  public void put(Object x) throws InterruptedException {
    lock.lock();  //   
    try {
      //   “    ”,   ;  “  ”    ,  x      。
      while (count == items.length)
        notFull.await();
      //  x      
      items[putptr] = x; 
      //  “put   putptr+1”;  “    ”,  putptr 0。
      if (++putptr == items.length) putptr = 0;
      //  “  ”  +1
      ++count;
      //   take  ,  take    notEmpty.await()  
      notEmpty.signal();
      //        
      System.out.println(Thread.currentThread().getName() + " put "+ (Integer)x);
    } finally {
      lock.unlock();  //    
    }
  }
  public Object take() throws InterruptedException {
    lock.lock();  //   
    try {
      //   “    ”,   ;  “  ”   ,  x      。
      while (count == 0) 
        notEmpty.await();
      //  x      
      Object x = items[takeptr]; 
      //  “take   takeptr+1”;  “    ”,  takeptr 0。
      if (++takeptr == items.length) takeptr = 0;
      //  “  ”  -1
      --count;
      //   put  ,  put    notFull.await()  
      notFull.signal();
      //        
      System.out.println(Thread.currentThread().getName() + " take "+ (Integer)x);
      return x;
    } finally {
      lock.unlock();  //    
    }
  } 
}
public class ConditionTest2 {
  private static BoundedBuffer bb = new BoundedBuffer();
  public static void main(String[] args) {
    //   10 “   ”, BoundedBuffer       (  0-9);
    //   10 “   ”, BoundedBuffer       。
    for (int i=0; i<10; i++) {
      new PutThread("p"+i, i).start();
      new TakeThread("t"+i).start();
    }
  }
  static class PutThread extends Thread {
    private int num;
    public PutThread(String name, int num) {
      super(name);
      this.num = num;
    }
    public void run() {
      try {
        Thread.sleep(1);  //     1ms
        bb.put(num);    //  BoundedBuffer     
      } catch (InterruptedException e) {
      }
    }
  }
  static class TakeThread extends Thread {
    public TakeThread(String name) {
      super(name);
    }
    public void run() {
      try {
        Thread.sleep(10);          //     1ms
        Integer num = (Integer)bb.take();  //  BoundedBuffer     
      } catch (InterruptedException e) {
      }
    }
  }
}

(한 번) 실행 결과:
p1 put  1 p4 put  4 p5 put  5 p0 put  0 p2 put  2 t0 take 1 p3 put  3 t1 take 4 p6 put  6 t2 take 5 p7 put  7 t3 take 0 p8 put  8 t4 take 2 p9 put  9 t5 take 3 t6 take 6 t7 take 7 t8 take 8 t9 take 9
결과 설명:
(01) Bounded Buffer 는 용량 이 5 인 버퍼 이 고 버퍼 에 Object 대상 이 저장 되 어 있 으 며 다 중 스 레 드 의 읽 기/쓰기 버퍼 를 지원 합 니 다.여러 스 레 드 가 '하나의 Bounded Buffer 대상' 을 조작 할 때 서로 배척 하 는 lock 을 통 해 버퍼 항목 에 대해 서로 배척 하 는 접근 을 합 니 다.또한 같은 Bounded Buffer 대상 의 모든 스 레 드 는 'notFull' 과 'notEmpty' 라 는 두 Condition 을 공유 합 니 다.
       notFull 은 쓰기 버퍼 를 제어 하 는 데 사 용 됩 니 다. notEmpty 는 읽 기 버퍼 를 제어 하 는 데 사 용 됩 니 다.버퍼 가 가득 찼 을 때 put 를 호출 하 는 스 레 드 는 notFull. await () 를 실행 하여 기 다 립 니 다.버퍼 가 가득 찬 상태 가 아 닐 때 대상 을 버퍼 에 추가 하고 버퍼 의 용량 count + 1 을 마지막 으로 notEmpty. signal () 버퍼 notEmpty 의 대기 스 레 드 (notEmpty. await 스 레 드 호출) 를 호출 합 니 다.즉, notFull 는 '버퍼 의 기록' 을 제어 합 니 다. 버퍼 에 데 이 터 를 기록 하면 notEmpty 의 대기 스 레 드 를 깨 웁 니 다.
       마찬가지 로 notEmpty 는 '버퍼 읽 기' 를 제어 합 니 다. 버퍼 데 이 터 를 읽 은 후에 notFull 의 대기 스 레 드 를 깨 웁 니 다.
(02) Condition Test 2 의 main 함수 에서 10 개의 "쓰기 스 레 드"를 시작 하여 Bounded Buffer 에 끊임없이 데 이 터 를 쓰기 (0 - 9 쓰기);동시에 10 개의 '읽 기 스 레 드' 를 시작 하여 Bounded Buffer 에서 데 이 터 를 계속 읽 습 니 다.
(03) 운행 결 과 를 간단하게 분석한다.
     1, p1 스 레 드 는 버퍼 에 1 을 기록 합 니 다.    이 때 버퍼 데이터:   | 1 |   |   |   |   |
     2, p4 스 레 드 는 버퍼 에 4 를 기록 합 니 다.    이 때 버퍼 데이터:   | 1 | 4 |   |   |   |
     3, p5 스 레 드 버퍼 에 5 를 기록 합 니 다.    이 때 버퍼 데이터:   | 1 | 4 | 5 |   |   |
     4, p0 스 레 드 는 버퍼 에 0 을 기록 합 니 다.    이 때 버퍼 데이터:   | 1 | 4 | 5 | 0 |   |
     5, p2 스 레 드 버퍼 에 2 를 기록 합 니 다.    이 때 버퍼 데이터:   | 1 | 4 | 5 | 0 | 2 |
     이때 버퍼 용량 은 5 입 니 다.버퍼 가 가득 찼 습 니 다!이 때 버퍼 에 데 이 터 를 쓰 려 면 put 에 있 는 notFull. await () 를 호출 하여 대기 하고 버퍼 가 가득 차지 않 은 상태 에서 만 계속 실행 할 수 있 습 니 다.
     6. t0 스 레 드 는 버퍼 에서 데이터 1 을 꺼 냅 니 다.이 때 버퍼 데이터:   |   | 4 | 5 | 0 | 2 |
     7, p3 스 레 드 는 버퍼 에 3 을 기록 합 니 다.    이 때 버퍼 데이터:   | 3 | 4 | 5 | 0 | 2 |
     8. t1 스 레 드 는 버퍼 에서 데 이 터 를 꺼 냅 니 다.이 때 버퍼 데이터:   | 3 |   | 5 | 0 | 2 |
     9, p6 스 레 드 는 버퍼 에 6 을 기록 합 니 다.    이 때 버퍼 데이터:   | 3 | 6 | 5 | 0 | 2 |      ...

좋은 웹페이지 즐겨찾기