AQS 동기 화 구성 요소--ReentrantLock 과 자물쇠

ReentrantLock 과 자물쇠
Synchronized 와 ReentrantLock 의 공통점 과 차이 점
4.567917.재 입 성:둘 다 재 입 성 을 가진다
  • 자물쇠 의 실현:Synchronized 는 jvm 에 의존 하여 이 루어 진 것 이 고 ReentrantLock 은 jdk 에 의 해 이 루어 진 것 이다.(하 나 는 운영 체제 차원 의 실현 이 고 다른 하 나 는 사용자 가 스스로 실현 한 것 으로 이해 할 수 있다.ReentrantLock 은 jvm 을 통 해 이 루어 진 것 입 니 다.우 리 는 jvm 소스 코드 를 읽 어서 이 루어 진 것 을 볼 수 있 습 니 다
  • 성능 차이:Synchronized 가 최적화 되 기 전에 Synchronized 의 성능 은 ReentrantLock 에 비해 많이 떨 어 졌 고 Synchronized 에 편향 자 물 쇠 를 도 입 했 습 니 다.경량급 자 물 쇠 는 자전 자물쇠 이후 에 이들 의 성능 차이 가 크 지 않 습 니 다.둘 다 사용 할 수 있 는 상황 에서 공식 적 으로 Synchronized 를 사용 하 는 것 을 추천 합 니 다.쓰기 가 더욱 간단 하기 때문에 Synchronized 의 최적화 는 ReentrantLock 의 cas 기술 을 참고 한 것 입 니 다
  • 기능 차이:편리 성,뚜렷 한 synchronized 의 사용 이 더욱 편리 하고 ReentrantLock 은 입자 도와 유연성 에서 Synchronized 보다 우수 합 니 다

  • ReentrantLock 만 의 기능
  • ReentrantLock 은 공평 자물쇠 인지 불공평 자물쇠 인지 지정 할 수 있 으 며 Synchronized 는 불공평 자물쇠 일 수 밖 에 없습니다.(공정 자 물 쇠 는 먼저 기다 리 는 라인 에서 자 물 쇠 를 먼저 얻 는 것 이다)
  • ReentrantLock 은 깨 워 야 할 형성 을 그룹 별로 깨 울 수 있 는 Condition 류 를 제공 합 니 다.synchronized 는 랜 덤 으로 스 레 드 를 깨 우 든 지 모든 스 레 드 를 깨 우 든 지..
  • ReentrantLock 은 잠 금 을 기다 리 는 스 레 드 를 중단 할 수 있 는 메커니즘 lock.locInterruptibly()를 제공 합 니 다.ReentrantLock 은 순환 호출 을 통 해 카 스 체 제 를 통 해 잠 금 을 추가 하 는 것 을 실현 합 니 다.성능 이 비교적 좋 은 것 은 스 레 드 가 커 널 에 들 어 가 는 차단 상 태 를 피 했 기 때문이다
  • @Slf4j
    public class LockExample2 {
    
        //     
        public static int clientTotal = 5000;
    
        //           
        public static int threadTotal = 200;
    
        public static int count = 0;
    
        private final static Lock lock = new ReentrantLock();
    
        public static void main(String[] args) throws Exception {
            ExecutorService executorService = Executors.newCachedThreadPool();
            final Semaphore semaphore = new Semaphore(threadTotal);
            final CountDownLatch countDownLatch = new CountDownLatch(clientTotal);
            for (int i = 0; i < clientTotal ; i++) {
                executorService.execute(() -> {
                    try {
                        semaphore.acquire();
                        add();
                        semaphore.release();
                    } catch (Exception e) {
                        log.error("exception", e);
                    }
                    countDownLatch.countDown();
                });
            }
            countDownLatch.await();
            executorService.shutdown();
            log.info("count:{}", count);
        }
    
        private static void add() {
            lock.lock();
            try {
                count++;
            } finally {
                lock.unlock();
            }
        }
    }

    우선 private final static Lock lock=new ReentrantLock()을 사용 하여 얻 은 인 스 턴 스 를 설명 한 다음 사용 합 니 다.
    lock.lock();
            try {
                count++;
            } finally {
                lock.unlock();
            }

    잠 금 추가 와 잠 금 해제 작업 을 진행 합 니 다.
    우 리 는 하나의 예 를 통 해 이 ReentrantReadWrite Lock 을 어떻게 사용 하 는 지 보고 있다.
    @Slf4j
    public class LockExample3 {
    
        private final Map map = new TreeMap<>();
    
        private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
    
        private final Lock readLock = lock.readLock();
    
        private final Lock writeLock = lock.writeLock();
    
        public Data get(String key) {
            readLock.lock();
            try {
                return map.get(key);
            } finally {
                readLock.unlock();
            }
        }
    
        public Set getAllKeys() {
            readLock.lock();
            try {
                return map.keySet();
            } finally {
                readLock.unlock();
            }
        }
    
        public Data put(String key, Data value) {
            writeLock.lock();
            try {
                return map.put(key, value);
            } finally {
                readLock.unlock();
            }
        }
    
        class Data {
    
        }
    }
    

    private final ReentrantReadWriteLock=new ReentrantReadWriteLock()을 통 해 ReentrantReadWriteLock 을 설명 한 다음 private final Lock readLock=lock.readLock()private final Lock writeLock=lock.writeLock()읽 기와 쓰기 자 물 쇠 를 각각 가 져 옵 니 다.우 리 는 이 맵 을 읽 을 때 읽 기 자 물 쇠 를 넣 고 쓸 때 자 물 쇠 를 쓴다.그러나 여기 서 문제 가 있 는 것 은 이 자물쇠 가 비관 적 인 자물쇠 라 는 것 이다.즉,자 물 쇠 를 쓸 때 읽 기 자 물 쇠 를 가지 고 있 으 면 안 된다 는 것 이다.읽 기 동작 이 특히 많 을 때 자 물 쇠 를 계속 집행 하지 못 하 게 할 가능성 이 높다.
    공식 적 인 예 를 들 어 배 워 보 겠 습 니 다.Stamped Lock.
    import java.util.concurrent.locks.StampedLock;
    
    public class LockExample4 {
    
        class Point {
            private double x, y;
            private final StampedLock sl = new StampedLock();
    
            void move(double deltaX, double deltaY) { // an exclusively locked method
                long stamp = sl.writeLock();
                try {
                    x += deltaX;
                    y += deltaY;
                } finally {
                    sl.unlockWrite(stamp);
                }
            }
    
            //          
            double distanceFromOrigin() { // A read-only method
                long stamp = sl.tryOptimisticRead(); //        
                double currentX = x, currentY = y;  //             
                if (!sl.validate(stamp)) { //                    ?
                    stamp = sl.readLock();  //    ,            
                    try {
                        currentX = x; //              
                        currentY = y; //              
                    } finally {
                        sl.unlockRead(stamp);
                    }
                }
                return Math.sqrt(currentX * currentX + currentY * currentY);
            }
    
            //         
            void moveIfAtOrigin(double newX, double newY) { // upgrade
                // Could instead start with optimistic, not read mode
                long stamp = sl.readLock();
                try {
                    while (x == 0.0 && y == 0.0) { //  ,          
                        long ws = sl.tryConvertToWriteLock(stamp); //       
                        if (ws != 0L) { //            
                            stamp = ws; //         
                            x = newX; //      
                            y = newY;  //      
                            break;
                        } else { //           
                            sl.unlockRead(stamp);  //        
                            stamp = sl.writeLock();  //                  
                        }
                    }
                } finally {
                    sl.unlock(stamp); //       
                }
            }
        }
    }

    앞 에 있 는 안 을 Stamped Lock 으로 바 꿔 보도 록 하 겠 습 니 다.
    @Slf4j
    public class LockExample5 {
    
        //     
        public static int clientTotal = 5000;
    
        //           
        public static int threadTotal = 200;
    
        public static int count = 0;
    
        private final static StampedLock lock = new StampedLock();
    
        public static void main(String[] args) throws Exception {
            ExecutorService executorService = Executors.newCachedThreadPool();
            final Semaphore semaphore = new Semaphore(threadTotal);
            final CountDownLatch countDownLatch = new CountDownLatch(clientTotal);
            for (int i = 0; i < clientTotal ; i++) {
                executorService.execute(() -> {
                    try {
                        semaphore.acquire();
                        add();
                        semaphore.release();
                    } catch (Exception e) {
                        log.error("exception", e);
                    }
                    countDownLatch.countDown();
                });
            }
            countDownLatch.await();
            executorService.shutdown();
            log.info("count:{}", count);
        }
    
        private static void add() {
            long stamp = lock.writeLock();
            try {
                count++;
            } finally {
                lock.unlock(stamp);
            }
        }
    }
    

    여기 가 예전 과 다른 점 이 바로...
       long stamp = lock.writeLock();
            try {
                count++;
            } finally {
                lock.unlock(stamp);
            }

    자 물 쇠 를 추가 하면 값 을 되 돌려 줍 니 다.자 물 쇠 를 풀 때 이 값 을 입력 해 야 합 니 다.

    좋은 웹페이지 즐겨찾기