Java 병발-RENTrantLock

1.프로필
재 접속 가능 한 잠 금 ReentrantLock 은 JDK 1.5 에서 도입 되 었 으 며,기능 상 synchronized 키워드 와 유사 하지만,기능 상 synchronized 보다 강력 하 며,재 접속 가능 외 에 도 ReentrantLock 은 4 가지 특성 을 가지 고 있다. 、 、 、 synchronized 가 만족 하지 못 하 는 장면 에서 공정 한 잠 금,중단 허용,시간 초과 설정,여러 조건 변수 가 필요 한 경우 ReentrantLock 사용 을 고려 해 야 합 니 다.
2.용법
ReenTrantLock 은 Lock 인 터 페 이 스 를 계 승 했 습 니 다.Lock 인 터 페 이 스 는 다음 과 같은 방법 이 있 습 니 다.
2.1 재 접속 가능
재 귀 자물쇠 라 고도 부 릅 니 다.같은 스 레 드 가 외부 방법 으로 자 물 쇠 를 가 져 올 때 이 스 레 드 에 들 어 가 는 내부 방법 은 자동 으로 자 물 쇠 를 가 져 옵 니 다.
void m1() {
lock.lock();
try {
    //    m2,     ,        
    m2();
} finally {
    lock.unlock()
}

}
void m2() {
lock.lock();
try {
    // do something
} finally {
    lock.unlock()
}

}
주:ReentrantLock 의 try-finally , finally 방법 이상 잠 금 이 풀 리 지 않도록 합 니 다.
2.2 인 터 럽 트 자물쇠 。 , , 。잠 금 의 lockInterruptibly 방법 을 호출 하면 잠 금 을 중단 할 수 있 습 니 다.이 방법 을 통 해 잠 금 을 가 져 올 때 다른 스 레 드 가 잠 금 을 가 져 오 기 를 기다 리 고 있다 면 이 스 레 드 는 중단 에 응답 할 수 있 습 니 다.즉, .즉,두 스 레 드 가 동시에 lock.lockInterruptibly()를 통 해 특정한 자 물 쇠 를 가 져 오 려 고 할 때 만약 에 이때 스 레 드 A 가 자 물 쇠 를 가 져 왔 고 스 레 드 B 가 기다 리 기만 한다 면 스 레 드 B 에 threadB.interrupt()방법 으로 스 레 드 B 의 대기 과정 을 중단 할 수 있 습 니 다.예 는 다음 과 같다.
public class ReentrantLockTest {
private static int account = 0;
private static ReentrantLock lock = new ReentrantLock();

public static void main (String [] args) {
    
    Thread t1 = new Thread(()->{
            try {
                lock.lockInterruptibly();
                System.out.println("  t1  :"+account++);
            } catch (InterruptedException e) {
                System.out.println("  t1    ");
            }finally {
                lock.unlock();
            }
        
    },"t1");
    
    Thread t2 = new Thread(()->{
            try {
                lock.lockInterruptibly();
                System.out.println("  t2  :"+account++);
                //   interrupt      t1
                t1.interrupt();
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
                System.out.println("  t2    ");
            }finally {
                lock.unlock();
            }
    
},"t2");
    t2.start();
    t1.start();
    
}

}
가능 한 실행 결 과 는:
주:위의 결 과 는 그 중의 한 가지 가능성 일 뿐 실제 운행 중 에 다른 결과 가 있 을 수 있 습 니 다.
일반적으로 중 단 된 사용 장면 은 다음 과 같은 몇 가지 가 있다.
  • 어떤 데스크 톱 응용 프로그램의 취소 단 추 를 눌 렀 을 때;
  • 특정한 조작 이 일정한 집행 시간 제한 을 초과 하여 중지 해 야 할 때
  • 여러 스 레 드 가 같은 일 을 하고 한 스 레 드 가 성공 하면 다른 스 레 드 를 취소 할 수 있 을 때
  • 한 스 레 드 중 하나 이상 의 오류 가 발생 하여 전체 그룹 이 계속 할 수 없 을 때
  • 응용 프로그램 이나 서비스 가 정지 되 어야 할 때

  • 2.3 공평 자물쇠
    잠 금 가 져 오기 순 서 는 요청 한 절대 시간 순서,즉 FIFO 에 부합 되 며,먼저 도착 한 스 레 드 에서 잠 금 을 우선 가 져 옵 니 다.이미지 의 말 에 따 르 면 장삼,이사,왕 이 는 슈퍼마켓 에 가서 쇼핑 을 했 는데 계산대 가 하나 밖 에 없 었 다.3 명 이 모두 물건 을 샀 고 계산 을 하려 고 했다.공평 한 자 물 쇠 를 준비 했다.장삼 은 계산대 에 사람 이 없 는 것 을 발견 하고 바로 계산대 로 달 려 갔다.이사 와 왕 이 는 장삼 이 앞 에 있 는 것 을 보고 순 순 히 줄 을 서서 불공평 한 자 물 쇠 를 계산 했다.장삼 은 첫 번 째 로 계산대 에 가서 계산 을 했 고 이사 와 왕 이 는 네 번 째 로 계산 했다.그러나 이사(李 四)는 장삼(張 三)이 아직 끝나 지 않 은 것 을 발견 하고 장삼(張 三)뒤에 줄 을 섰 다.이때 왕 이도 왔 다.장삼(張 三)이 다 끝 난 것 을 발견 하 자 바로 앞 다 투어 계산 하 러 갔 고 이사(李 四)는 하늘 을 쳐 다 보 며"불공평 해"라 고 장탄 했다.
    public class FairTest {
    
    //   true   ReentrantLock     ,false     ,   false    
    private  ReentrantLock lock = new ReentrantLock(true);
    
    public void testFair() {
        lock.lock();
        try {
            System.out.println(Thread.currentThread().getName() +"    ");
        }finally {
            lock.unlock();
        }     
    }
    
    public static void main(String[] args) {
        FairTest fairLock = new FairTest();
        Runnable runnable = () -> {
            System.out.println(Thread.currentThread().getName()+"  ");
            fairLock.testFair();
        };
        Thread[] threadArray = new Thread[5];
        for (int i=0; i<5; i++) {
            threadArray[i] = new Thread(runnable);
            threadArray[i].start();
        }
    }
    

    }
    가능 한 실행 결과:
    이 를 통 해 알 수 있 듯 이 자물쇠 의 획득 순서 와 스 레 드 의 요청 자물쇠 의 순서 가 일치 합 니 다.
    2.4 설정 시간 초과
    try Lock()방법 은 자 물 쇠 를 한 번 가 져 오 려 고 시도 합 니 다.자 물 쇠 를 성공 적 으로 얻 은 후에 true 로 돌아 갑 니 다.그렇지 않 으 면 즉시 false 로 돌아 갑 니 다.그리고 스 레 드 는 즉시 다른 일 을 할 수 있 습 니 다.try Lock(long timeout,TimeUnit unit)은 시간 초과 매개 변 수 를 가 진 잠 금 을 신청 하 는 방법 입 니 다.차단 시간 은 주어진 값 을 초과 하지 않 습 니 다.주어진 시간 내 에 잠 금 을 성공 적 으로 가 져 오 면 true 로 돌아 갑 니 다.그렇지 않 으 면 시간 이 초 과 될 때 까지 막 힌 다음 flase 로 돌아 갑 니 다.
    public class TimeoutTest{
    private ReentrantLock lock = new ReentrantLock();
    
    public void testTryLock() {
        if (lock.tryLock()) {
            try {
                System.out.println(Thread.currentThread().getName() + "    ");
                Thread.sleep(1000);
            }catch(Exception e){
                e.printStackTrace();
            }finally {
                lock.unlock();
            }           
        }else {
            System.out.println(Thread.currentThread().getName() + "      ");
        }
    }
    
    public void testTryLockWithTimeout() {
        try {
            if (lock.tryLock(1, TimeUnit.SECONDS)){
                try {
                    System.out.println(Thread.currentThread().getName() + " 1s     ");
                    Thread.sleep(1000);
                }finally {
                    lock.unlock();
                }                
            }else {
                System.out.println(Thread.currentThread().getName() + " 1s       ");
            }
        }catch (InterruptedException e) {
            System.out.println(Thread.currentThread().getName() + " was interrupted");
        }      
    }
    
    public static void main(String [] args) {
        TimeoutTest timeouttest = new TimeoutTest();
        Runnable runnable = () -> {
            System.out.println(Thread.currentThread().getName()+"  ");
            timeouttest.testTryLock();
            //timeouttest.testTryLockWithTimeout();
        };
        Thread[] threadArray = new Thread[5];
        for (int i=0; i<5; i++) {
            threadArray[i] = new Thread(runnable);
            threadArray[i].start();
        }
    }

    }
    testTryLock()실행 가능 한 실행 결과:
    testTry Lock WithTimeout()실행 가능 한 실행 결과:
    2.5 여러 조건 을 귀속 가능
    이것 은 synchronize 와 가장 중요 한 차이 점 입 니 다.synchronize 는 하나의 조건 에 해당 하고 ReentrantLock 은 여러 조건 을 연결 할 수 있 습 니 다.이것 은 여러 조건 변수 가 필요 한 장면 에서 ReentrantLock,예 를 들 어 대기 열 을 막 는 것 만 고려 할 수 있 습 니 다.대기 열 차단 요구: , , , .아래 코드 는 JDK 1.8 에서 Array BlockingQueue 의 소스 코드 를 발췌 한 것 으로 간략 합 니 다.더 많은 것 을 알 고 싶 으 면 Array BlockingQueue 의 소스 코드 를 읽 거나 블 로그'차단 대기 열과 Array BlockingQueue 소스 코드 분석(JDK 1.8)'을 참고 하 십시오.
    public class ArrayBlockingQueue {
    
    final Object[] items; //       
    int takeIndex; //            
    int putIndex; //          
    int count; //        
    final ReentrantLock lock; //        
    private final Condition notEmpty; //       
    private final Condition notFull; //       
    
    public ArrayBlockingQueue(int capacity) {
        this(capacity, false);
    }
    
    public ArrayBlockingQueue(int capacity, boolean fair) {
        if (capacity <= 0)
            throw new IllegalArgumentException();
        this.items = new Object[capacity];
        lock = new ReentrantLock(fair);
        notEmpty = lock.newCondition();
        notFull =  lock.newCondition();
    }
    //    
    private void enqueue(E x) {
        final Object[] items = this.items;
        items[putIndex] = x;
        if (++putIndex == items.length)
            putIndex = 0;
        count++;
        notEmpty.signal();
    }
    //    
    private E dequeue() {
        final Object[] items = this.items;
        @SuppressWarnings("unchecked")
        E x = (E) items[takeIndex];
        items[takeIndex] = null;
        if (++takeIndex == items.length)
            takeIndex = 0;
        count--;
        notFull.signal();
        return x;
    }
    
    //    ,               
    public void put(E e) throws InterruptedException {
        checkNotNull(e);
        final ReentrantLock lock = this.lock;
        lock.lockInterruptibly();
        try {
            //  while           ,     
            while (count == items.length)
                notFull.await();
            enqueue(e);
        } finally {
            lock.unlock();
        }
    }
    
    //       ,               
    public E take() throws InterruptedException {
        final ReentrantLock lock = this.lock;
        lock.lockInterruptibly();
        try {
            //  while           ,     
            while (count == 0)
                notEmpty.await();
            return dequeue();
        } finally {
            lock.unlock();
        }
    }
    
    private static void checkNotNull(Object v) {
        if (v == null)
            throw new NullPointerException();
    }

    }
    3.원리
    원 리 는 블 로그 인 을 참고 하 십시오.이 블 로 그 는 매우 상세 하고 깊이 가 있 습 니 다.
    4.총화
    본 고 는 ReentrantLock 의 4 가지 특성 、 、 、 에 착안 하여 ReentrantLock 의 기본 적 인 용법 을 정리 하여 다음 에 ReentrantLock 의 원리 와 일상적인 개발 에서 ReentrantLock 을 능숙 하 게 사용 하 는 데 기반 을 다 져 주 었 다.

    좋은 웹페이지 즐겨찾기