자바 및 하 도 급 학습 시리즈:잠 금 및 Condition 조건 재 입력

14586 단어 자바 병발
재 접속 자물쇠
여기 synchronized,wait,notify 방법의 대체 품(또는 증강 판)-재 입 자 물 쇠 를 소개 합 니 다.재 입 자 물 쇠 는 이상 의 내용 을 완전히 대체 할 수 있다.또한 재 접속 잠 금 의 성능 은 synchronized 보다 훨씬 높 지만 jdk 6.0 부터 jdk 는 synchronized 에 대해 대량의 최적화 를 하여 이들 의 성능 차이 가 크 지 않다.
  재 입 자 물 쇠 는 java.util.concurrent.locks.ReentrantLock 류 를 사용 하여 이 루어 집 니 다.그것 의 몇 가지 중요 한 방법 은 다음 과 같다.
lock():   ,        ,   。
lockInterruptibly():   ,       。
tryLock():     ,    ,  truefalse。      ,    。
tryLock(long time, TimeUnit unit):           。
unLock():   。

메모:잠 금 해제 작업 lock.unlock()을 finally 자구 에 넣 는 것 이 중요 합 니 다.이렇게 하면 임계 구역 의 코드 에 이상 이 생 겨 도 자 물 쇠 를 풀 어야 합 니 다.그렇지 않 으 면 다른 스 레 드 는 영원히 막 힐 것 입 니 다.
잠 금 재 입 간단 한 사례:lock 과 unLock
/**
 * Created by niehongtao on 16/7/8.
 * 3.1   
 */
public class ReenterLock implements Runnable {
    public static ReentrantLock lock = new ReentrantLock();
    public static int i = 0;

    @Override
    public void run() {
        for (int j = 0; j < 10000000; j++) {
            lock.lock();
            try {
                i++;
            } finally {
                lock.unlock();
            }
        }
    }


    public static void main(String[] args) throws InterruptedException {
        ReenterLock rl = new ReenterLock();
        Thread t1 = new Thread(rl);
        Thread t2 = new Thread(rl);
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        System.out.println(i);
    }
}

*8195°상기 코드 는 재 접속 자 물 쇠 를 사용 하여 임계 구역 자원 i 를 보호 하고 다 중 스 레 드 가 i 작업 에 대한 안전성 을 확보 합 니 다.이 코드 를 통 해 알 수 있 듯 이 synchronized 에 비해 잠 금 을 다시 넣 는 것 은 표시 되 는 작업 과정 이 있 습 니 다.개발 자 는 자 물 쇠 를 언제 넣 을 지,언제 자 물 쇠 를 풀 지 수 동 으로 지정 해 야 한다.그 렇 기 때문에 재 접속 자 물 쇠 는 논리 적 통제 에 대한 유연성 이 synchronized 보다 훨씬 좋 지만 주의해 야 할 것 은 임계 구역 을 제시 할 때 자 물 쇠 를 풀 어야 한 다 는 것 이다.그렇지 않 으 면 다른 스 레 드 는 임계 구역 을 다시 방문 할 기회 가 없다 는 것 이다.
*8195:8195:자 물 쇠 를 다시 넣 을 때 같은 스 레 드 는 여러 번 자 물 쇠 를 얻 을 수 있 지만 자 물 쇠 를 풀 때 도 같은 횟수 를 풀 어야 합 니 다.그렇지 않 으 면 이상 이 생 길 수 있다.
잠 금 재 입 중단 응답:lockInterruptibly
/**
 * Created by niehongtao on 16/7/8.
 *     
 */
public class IntLock implements Runnable {
    public static ReentrantLock lock1 = new ReentrantLock();
    public static ReentrantLock lock2 = new ReentrantLock();
    int lock;

    /**
     *       ,      
     *
     * @param lock
     */
    public IntLock(int lock) {
        this.lock = lock;
    }

    @Override
    public void run() {
        try {
            if (lock == 1) {
                lock1.lockInterruptibly();
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                }
                lock2.lockInterruptibly();
            } else {
                lock2.lockInterruptibly();
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                }
                lock1.lockInterruptibly();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            if (lock1.isHeldByCurrentThread()) {
                lock1.unlock();
            }
            if (lock2.isHeldByCurrentThread()) {
                lock2.unlock();
            }
            System.out.println(Thread.currentThread().getId() + ":    ");
        }

    }

    public static void main(String[] args) throws InterruptedException {
        IntLock il1 = new IntLock(1);
        IntLock il2 = new IntLock(2);
        Thread t1 = new Thread(il1);
        Thread t2 = new Thread(il2);
        t1.start();
        t2.start();
        Thread.sleep(1000);
        //         
        t2.interrupt();
    }
}

잠 금 신청 대기 시간:lock.try Lock 의 두 가지 방법
/**
 * Created by niehongtao on 16/7/8.
 *        
 */
public class TimeLock implements Runnable {
    public static ReentrantLock lock = new ReentrantLock();



    @Override
    public void run() {
        try {
            if (lock.tryLock(5, TimeUnit.SECONDS)) {
                Thread.sleep(6000);
            } else {
                System.out.println("get lock failed");
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }

    }


    public static void main(String[] args) {
        TimeLock tl = new TimeLock();
        Thread t1 = new Thread(tl);
        Thread t2 = new Thread(tl);
        t1.start();
        t2.start();
    }
}


공정 자물쇠:ReentrantLock 의 구조 함 수 는 매개 변 수 를 추가 할 수 있 습 니 다.
조건 조건
  만약 여러분 이 obj.wait 와 obj.notify 방법 을 이해 했다 면 Condition 대상 을 쉽게 이해 할 수 있 을 것 입 니 다.그것 은 wait 와 notify 방법의 작용 과 대체로 같다.그러나 wait 와 notify 방법 은 synchronized 키워드 와 합작 하여 사용 되 며,Condition 은 재 접속 잠 금 과 연 결 됩 니 다.Condition 의 new Condition()방법 을 통 해 현재 잠 금 으로 연 결 된 Condition 인 스 턴 스 를 만 들 수 있 습 니 다.Condition 대상 을 이용 하면 우 리 는 스 레 드 를 적당 한 시간 에 기다 리 게 하거나 특정한 시간 에 통 지 를 받 아 계속 실행 할 수 있 습 니 다.
Condition 이 제공 하 는 기본 적 인 방법 은 다음 과 같다.
 void   await() 
          Causes the current thread to wait until it is signalled or interrupted.
 boolean    await(long time, TimeUnit unit) 
          Causes the current thread to wait until it is signalled or interrupted, or the specified waiting time elapses.
 long   awaitNanos(long nanosTimeout) 
          Causes the current thread to wait until it is signalled or interrupted, or the specified waiting time elapses.
 void   awaitUninterruptibly() 
          Causes the current thread to wait until it is signalled.
 boolean    awaitUntil(Date deadline) 
          Causes the current thread to wait until it is signalled or interrupted, or the specified deadline elapses.
 void   signal() 
          Wakes up one waiting thread.
 void   signalAll() 
          Wakes up all waiting threads.


상기 방법의 구체 적 인 의 미 는 다음 과 같다.
await()방법 은 현재 스 레 드 가 기다 리 는 동시에 현재 자 물 쇠 를 방출 합 니 다.다른 스 레 드 에서 signal()또는 signal All()방법 을 사용 할 때 스 레 드 는 다시 자 물 쇠 를 얻 고 계속 실 행 됩 니 다.스 레 드 가 중단 되 었 을 때 도 뛰 어 나 와 기다 릴 수 있 습 니 다.이것 은 obj.wait 방법 과 매우 비슷 하 다.
await Uninterruptibly()방법 은 await()방법 과 기본적으로 같 지만 대기 중 응답 이 중단 되 지 않 습 니 다.
signal()방법 은 대기 중인 스 레 드 를 깨 우 는 데 사 용 됩 니 다.이것 은 obj.notify 방법 과 유사 합 니 다.
단순 예시
/**
 * Created by niehongtao on 16/7/8.
 * Condition  
 */
public class ReenterLockcondition implements Runnable {
    public static ReentrantLock lock = new ReentrantLock();
    public static Condition condition = lock.newCondition();



    @Override
    public void run() {
        lock.lock();
        try {
            condition.await();
            System.out.println("thread is going on");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }

    }

    public static void main(String[] args) throws InterruptedException {
        ReenterLockcondition rlc = new ReenterLockcondition();
        Thread t1 = new Thread(rlc);
        t1.start();
        Thread.sleep(2000);
        //         
        lock.lock();
        condition.signal();
        lock.unlock();
    }
}


*8195°코드 에서 lock 이 연결 되 어 있 는 Condition 대상 을 만 드 는 것 을 들 은 적 이 있 습 니 다.코드 15 줄 은 Condition 대상 에서 스 레 드 를 기다 리 도록 요구 합 니 다.코드 32 줄 은 주 스 레 드 에서 알림 을 보 내 Condition 에서 기다 리 는 스 레 드 가 계속 실 행 될 수 있 음 을 알려 줍 니 다.
*8195:8195:obj.wait 는 notify 방법 과 마찬가지 로 스 레 드 가 Condition.wait 를 사용 할 때 스 레 드 에 관련 된 재 접속 자 물 쇠 를 가 져 오 라 고 요구 합 니 다.Condition.wait 가 호출 되면 이 스 레 드 는 이 자 물 쇠 를 방출 합 니 다.마찬가지 로 Condition.signal 방법 이 호출 될 때 도 스 레 드 에 관련 자 물 쇠 를 먼저 가 져 오 라 고 요구 합 니 다.signal 방법 이 호출 되면 시스템 은 현재 condition 대상 의 대기 열 에서 스 레 드 를 깨 웁 니 다.스 레 드 가 깨 어 나 면 바 인 딩 된 잠 금 을 다시 시도 합 니 다.성공 적 으로 가 져 오 면 계속 실행 할 수 있 습 니 다.따라서 signal 방법 이 호출 된 후에 관련 자 물 쇠 를 풀 고 깨 어 난 스 레 드 에 겸손 하 게 양보 하여 계속 실행 할 수 있 도록 해 야 합 니 다.예 를 들 어 이 예 에서 33 번 째 줄 은 재 입 자 물 쇠 를 풀 었 다.24 번 째 줄 을 생략 하면 스 레 드 t1 을 깨 웠 지만 다시 자 물 쇠 를 얻 을 수 없 기 때문에 진정 으로 계속 실행 할 수 없다.
  jdk 내부 에서 재 입 자물쇠 와 Condition 대상 이 광범 위 하 게 사용 되 고 뒤에 언급 된 라인 이 안전 한 용기 입 니 다.그들의 내용 은 재 입 자물쇠 와 Condition 대상 의 그림자 가 있 습 니 다.

좋은 웹페이지 즐겨찾기