자바 및 하 도 급 학습 시리즈:잠 금 및 Condition 조건 재 입력
14586 단어 자바 병발
여기 synchronized,wait,notify 방법의 대체 품(또는 증강 판)-재 입 자 물 쇠 를 소개 합 니 다.재 입 자 물 쇠 는 이상 의 내용 을 완전히 대체 할 수 있다.또한 재 접속 잠 금 의 성능 은 synchronized 보다 훨씬 높 지만 jdk 6.0 부터 jdk 는 synchronized 에 대해 대량의 최적화 를 하여 이들 의 성능 차이 가 크 지 않다.
재 입 자 물 쇠 는 java.util.concurrent.locks.ReentrantLock 류 를 사용 하여 이 루어 집 니 다.그것 의 몇 가지 중요 한 방법 은 다음 과 같다.
lock(): , , 。
lockInterruptibly(): , 。
tryLock(): , , true, false。 , 。
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 대상 의 그림자 가 있 습 니 다.