자바 의 잠 금 분류 및 사용 방법

19491 단어 자바자물쇠.쓰다
Lock 과 synchronized
자 물 쇠 는 공유 자원 에 대한 접근 을 제어 하 는 도구 이다
  • Lock 과 synchronized.이 두 가 지 는 가장 만 든 자물쇠 이다.그들 은 모두 스 레 드 안전 의 목적 을 달성 할 수 있 지만 사용 과 기능 에 있어 비교적 큰 차이 가 있다
  • Lock 은 synchronized 를 완전히 대체 하 는 것 이 아니 라 synchronized 를 사용 하 는 것 이 적합 하지 않 거나 요 구 를 만족 시 키 지 못 할 때 고급 기능 을 제공 합 니 다. 
  • Lock 에서 가장 흔히 볼 수 있 는 것 은 ReentrantLock 실현 이다.
  • 왜 Lock 이 필요 해?
  • syn 효율 이 낮 습 니 다.자물쇠 의 방출 상황 이 적 습 니 다.자 물 쇠 를 얻 으 려 고 할 때 시간 초과 설정 을 할 수 없고 자 물 쇠 를 얻 으 려 고 하 는 스 레 드 를 중단 할 수 없습니다
  • 4.567917.유연성 이 부족 하고 자 물 쇠 를 추가 하고 방출 하 는 시기 가 단일 하 며 모든 자 물 쇠 는 하나의 조건(특정한 대상)만 있 기 때문에 부족 할 수 있 습 니 다자 물 쇠 를 성공 적 으로 가 져 왔 는 지 알 수 없습니다.
    주요 방법
    Lock();     
    가장 일반적인 자 물 쇠 를 얻 습 니 다.가장 좋 은 실천 은 finally 에서 자 물 쇠 를 방출 하 는 것 입 니 다.이상 이 발생 할 때 자 물 쇠 는 반드시 방출 됩 니 다.
    
        /**
         *   :Lock   syn  ,          
         *             finally    ,               
         */
        private static Lock lock = new ReentrantLock();
     
        public static void main(String[] args) {
            lock.lock();
            try {
                //         
                System.out.println(Thread.currentThread().getName() + "      ");
            } finally {
                lock.unlock();
            }
        }
    tryLock(long time,TimeUnit unit);시간 을 초과 하면 포기 하 다.
    자 물 쇠 를 가 져 오 는 데 사용 합 니 다.현재 자물쇠 가 다른 스 레 드 에 점용 되 지 않 으 면 성공 을 가 져 오 면 true 로 돌아 갑 니 다.그렇지 않 으 면 false 로 돌아 가 자 물 쇠 를 가 져 오 는 데 실 패 했 습 니 다.
    
    /**
         *   : TryLock    
         */
        static class TryLockDeadlock implements Runnable {
     
            int flag = 1;
     
            static Lock lock1 = new ReentrantLock();
            static Lock lock2 = new ReentrantLock();
     
            @Override
            public void run() {
                for (int i = 0; i < 100; i++) {
                    if (flag == 1) {
                        try {
                            if (lock1.tryLock(800, TimeUnit.MILLISECONDS)) {
                                try {
                                    System.out.println("  1     1");
                                    Thread.sleep(new Random().nextInt(1000));
                                    if (lock2.tryLock(800,TimeUnit.MILLISECONDS)){
                                        try {
                                            System.out.println("  1     2");
                                            System.out.println("  1      2  ");
                                            break;
                                        }finally {
                                            lock2.unlock();
                                        }
                                    }else{
                                        System.out.println("  1   2  ,   ");
                                    }
                                } finally {
                                    lock1.unlock();
                                    Thread.sleep(new Random().nextInt(1000));
                                }
                            } else {
                                System.out.println("  1   1  ,   ");
                            }
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
     
                    if (flag == 0) {
                        try {
                            if (lock2.tryLock(3000, TimeUnit.MILLISECONDS)) {
                                try {
                                    System.out.println("  2     2");
                                    Thread.sleep(new Random().nextInt(1000));
                                    if (lock1.tryLock(800,TimeUnit.MILLISECONDS)){
                                        try {
                                            System.out.println("  2     1");
                                            System.out.println("  2      2  ");
                                            break;
                                        }finally {
                                            lock1.unlock();
                                        }
                                    }else{
                                        System.out.println("  2   1  ,   ");
                                    }
                                } finally {
                                    lock2.unlock();
                                    Thread.sleep(new Random().nextInt(1000));
                                }
                            } else {
                                System.out.println("  2   2  ,    ");
                            }
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
     
            public static void main(String[] args) {
                TryLockDeadlock r1 = new TryLockDeadlock();
                TryLockDeadlock r2 = new TryLockDeadlock();
                r1.flag = 1;
                r2.flag = 0;
                new Thread(r1).start();
                new Thread(r2).start();
            }
        }
     
        :
      1     1
      2     2
      1   2  ,   
      2     1
      2      2  
      1     1
      1     2
      1      2  
    lockInterruptibly(); 인 터 럽 트
    tryLock(long time,TimeUnit unit)이 시간 초과 시간 을 무한 으로 설정 한 것 과 같 습 니 다.잠 금 을 기다 리 는 과정 에서 스 레 드 가 중 단 될 수 있 습 니 다.
    
    /**
         *   :       ,   
         */
        static class LockInterruptibly implements Runnable {
     
            private Lock lock = new ReentrantLock();
     
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName() + "     ");
                try {
                    lock.lockInterruptibly();
                    try {
                        System.out.println(Thread.currentThread().getName() + "     ");
                        Thread.sleep(5000);
                    } catch (InterruptedException e) {
                        System.out.println(Thread.currentThread().getName() + "       ");
                    } finally {
                        lock.unlock();
                        System.out.println(Thread.currentThread().getName() + "    ");
                    }
                } catch (InterruptedException e) {
                    System.out.println(Thread.currentThread().getName() + "        ");
                }
            }
     
            public static void main(String[] args) {
                LockInterruptibly lockInterruptibly = new LockInterruptibly();
                Thread thread0 = new Thread(lockInterruptibly);
                Thread thread1 = new Thread(lockInterruptibly);
                thread0.start();
                thread1.start();
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                thread0.interrupt();
            }
        }
     
        :
    Thread-0     
    Thread-1     
    Thread-0     
    Thread-0       
    Thread-0    
    Thread-1     
    Thread-1    
    Java 잠 금 분류:

    낙관적 자물쇠 와 비관 적 자물쇠:
    낙관적 자물쇠:
    비교적 낙관적 이 고 자신 이 조작 을 처리 할 때 다른 스 레 드 가 방해 되 지 않 을 것 이 라 고 생각 하기 때문에 조작 대상 을 잠 그 지 않 습 니 다.
    4.567917.업데이트 할 때 제 가 수정 한 동안 의 데이터 가 바 뀌 었 는 지 비교 해 보 세 요.없 으 면 정상 적 인 수정 데이터 입 니 다4.567917.만약 에 데이터 가 제 가 처음에 받 은 것 과 다 르 면 다른 사람들 이 이 시간 안에 잘못 을 고치 면 포기,잘못 보고,재 시도 등 전략 을 선택 할 것 입 니 다4.567917.낙관적 인 자물쇠 의 실현 은 일반적으로 CAS 알고리즘 을 이용 하여 이 루어 진다.
    열세:
    ABA 문 제 를 일 으 킬 수 있 지만 수정 한 건 지 모 르 겠 어 요.
    사용 필드:
    동시 쓰기 가 적은 경우 에 적합 합 니 다.대부분 읽 는 장면 입 니 다.잠 금 을 넣 지 않 으 면 읽 을 수 있 는 성능 이 크게 향상 되 었 습 니 다.
    비관 자물쇠:
    비관 적 입 니 다.만약 에 제 가 이 자원 을 잠 그 지 않 으 면 다른 사람 이 다 투 게 되 고 데이터 결과 가 잘못 되 기 때문에 조작 대상 을 잠 글 것 이 라 고 생각 합 니 다.자바 에서 비관 적 인 자물쇠 의 실현 은 바로 syn 과 Lock 관련 유형 입 니 다.
    열세:
    4.567917.차단 과 각성 이 가 져 온 성능 약점4.567917.자 물 쇠 를 가 진 스 레 드 가 영구적 으로 막 히 면 예 를 들 어 무한 순환,자물쇠 잠 금 등 활성 문제 에 부 딪 히 면 이 스 레 드 가 자 물 쇠 를 풀 어 주 기 를 기다 리 는 몇 개의 스 레 드 는 영원히 실 행 될 수 없다4.567917.우선 순위 반전,우선 순위 가 낮은 스 레 드 가 자 물 쇠 를 가 져 오 거나 풀 리 지 않 는 것 이 비교적 느 리 면 이 문 제 를 초래 할 수 있다.
    사용 필드:
    동시 다발 기록 이 많은 경우 에 적합 하 며 임계 구역 의 잠 금 시간 이 비교적 긴 경우 에 적 용 됩 니 다.
    임계 구역 에 IO 조작 이 있 습 니 다임계 구역 코드 가 복잡 하거나 순환 량 이 크다임계 지역 의 경쟁 이 매우 치열 하 다.
    재 접속 가능 한 자물쇠:
    다시 들 어 갈 수 있다 는 것 은 어떤 스 레 드 가 이미 어떤 자 물 쇠 를 얻 었 기 때문에 자물쇠 가 생기 지 않 고 다시 자 물 쇠 를 얻 을 수 있다 는 것 이다.
    ReentrantLock 과... synchronized 는 모두 잠 금 을 다시 넣 을 수 있 습 니 다.
    
    //           
        static class RecursionDemo{
     
            public static ReentrantLock lock = new ReentrantLock();
     
            private static void accessResource(){
                lock.lock();
                try {
                    System.out.println("        ");
                    if (lock.getHoldCount() < 5){
                        System.out.println("     "+lock.getHoldCount()+" ");
                        accessResource();
                    }
                }finally {
                    lock.unlock();
                }
            }
     
            public static void main(String[] args) {
                new RecursionDemo().accessResource();
            }
        }
     
     
        :
            
         1 
            
         2 
            
         3 
            
         4 
            
    ReentrantLock 의 다른 방법
  • isHeldByCurrentThread 는 자물쇠 가 현재 스 레 드 에 보유 되 어 있 는 지 알 수 있 습 니 다
  • getQueueLength()는 현재 이 자 물 쇠 를 기다 리 고 있 는 대기 열 이 얼마나 긴 지 되 돌 릴 수 있 습 니 다.보통 이 두 가지 방법 은 개발 과 디 버 깅 할 때 사용 하 는 것 입 니 다.접속 후 사용 하 는 것 이 많 지 않 습 니 다

  • 공평 자물쇠 와 불공평 자물쇠
    4.567917.공평 이란 스 레 드 가 요구 하 는 순서에 따라 자 물 쇠 를 분배 하 는 것 을 말한다4
  • 불공평 이란 완전히 요구 하 는 순서에 따라 일정한 상황 에서 새치기 할 수 있 는 것 을 말한다.
  • 4.567917.불공평 한 자 물 쇠 는 깨 우 는 데 가 져 오 는 공백 기 를 피 할 수 있다.
    
    /**
     *   :          
     */
    class FairLock{
     
        public static void main(String[] args) {
            PrintQueue printQueue = new PrintQueue();
            Thread[] thread = new Thread[10];
            for (int i = 0; i < 10; i++) {
                thread[i] = new Thread(new Job(printQueue));
            }
     
            for (int i = 0; i < 5; i++) {
                thread[i].start();
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
     
    }
     
    class Job implements Runnable{
     
        PrintQueue printQueue;
     
        public Job(PrintQueue printQueue) {
            this.printQueue = printQueue;
        }
     
        @Override
        public void run() {
            System.out.println(Thread.currentThread().getName()+"    ");
            printQueue.printJob(new Object());
            System.out.println(Thread.currentThread().getName()+"    ");
        }
    }
     
    class PrintQueue{    
        // true   ,false    
        private  Lock queueLock = new ReentrantLock(true);
        public void printJob(Object document){
            queueLock.lock();
            try {
                int duration = new Random().nextInt(10)+1;
                System.out.println(Thread.currentThread().getName()+"    ,  "+duration+" ");
                Thread.sleep(duration * 1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                queueLock.unlock();
            }
     
            queueLock.lock();
            try {
                int duration = new Random().nextInt(10)+1;
                System.out.println(Thread.currentThread().getName()+"    ,  "+duration+" ");
                Thread.sleep(duration * 1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                queueLock.unlock();
            }
     
        }
    }
     
        :
    Thread-0    
    Thread-0    ,  10 
    Thread-1    
    Thread-2    
    Thread-3    
    Thread-4    
    Thread-1    ,  2 
    Thread-2    ,  2 
    Thread-3    ,  2 
    Thread-4    ,  4 
    Thread-0    ,  2 
    Thread-0    
    Thread-1    ,  7 
    Thread-1    
    Thread-2    ,  8 
    Thread-2    
    Thread-3    ,  3 
    Thread-3    
    Thread-4    ,  8 
    Thread-4    
     
    true  false      :
    Lock queueLock = new ReentrantLock(false);
        :
    Thread-0    ,  7 
    Thread-1    
    Thread-2    
    Thread-3    
    Thread-4    
    Thread-0    ,  9 
    Thread-0    
    Thread-1    ,  3 
    Thread-1    ,  2 
    Thread-1    
    Thread-2    ,  4 
    Thread-2    ,  7 
    Thread-2    
    Thread-3    ,  10 
    Thread-3    ,  2 
    Thread-3    
    Thread-4    ,  7 
    Thread-4    ,  8 
    Thread-4    
    공유 자물쇠 와 열 쇠:
    4.567917.배타 적 자 물 쇠 는 독점 자물쇠 라 고도 부 르 는데 독점 자물쇠4.567917.공유 자 물 쇠 는 읽 기 자물쇠 라 고도 부 릅 니 다.공유 자 물 쇠 를 얻 은 후에 데 이 터 를 볼 수 있 지만 수정 하고 삭제 할 수 없습니다.다른 스 레 드 는 이때 도 공유 자 물 쇠 를 얻 을 수 있 고 볼 수 있 지만 데 이 터 를 수정 하고 삭제 할 수 없습니다4.567917.공유 자물쇠 와 배타 자물쇠 의 전형 은 읽 기와 쓰기 자물쇠 이다. ReentrantReadWriteLock,읽 기 자 물 쇠 는 공유 자물쇠,쓰기 자 물 쇠 는 독점 자물쇠
    읽 기와 쓰기 자물쇠 의 역할:
    4.567917.읽 기와 쓰기 자물쇠 가 없 기 전에 우 리 는 ReentrantLock 을 사용한다 고 가정 합 니 다.그러면 우 리 는 스 레 드 안전 을 보장 하지만 일정한 자원 도 낭비 합 니 다.여러 개의 읽 기 작업 을 동시에 진행 하고 스 레 드 안전 문제 가 없습니다읽 는 곳 에서 읽 기 자 물 쇠 를 사용 하고 쓰 는 곳 에서 쓰기 자 물 쇠 를 사용 하여 유연 하 게 제어 한다.만약 에 자 물 쇠 를 쓰 지 않 은 상황 에서 읽 기 는 막힘 이 없고 프로그램의 집행 효율 을 높 인 다.
    자물쇠 읽 기 규칙:
    4.567917.여러 개의 스 레 드 값 이 읽 기 자 물 쇠 를 신청 하면 모두 4.567918 에 신청 할 수 있 습 니 다.
    4
  • 하나 또는 여러 개 를 같이 읽 거나 한 개 를 쓰 거나 둘 은 동시에 신청 하지 않 고 하나의 자물쇠 만 존재 합 니 다.
  • 
    /**
     *   :         ,     
     */
    class CinemaReadWrite{
        private static ReentrantReadWriteLock reentrantReadWriteLock = new ReentrantReadWriteLock();
        private static ReentrantReadWriteLock.ReadLock readLock = reentrantReadWriteLock.readLock();
        private static ReentrantReadWriteLock.WriteLock writeLock = reentrantReadWriteLock.writeLock();
     
        private static void read(){
            readLock.lock();
            try {
                System.out.println(Thread.currentThread().getName() + "     ,    ");
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                System.out.println(Thread.currentThread().getName() + "     ");
                readLock.unlock();
            }
        }
     
        private static void write(){
            writeLock.lock();
            try {
                System.out.println(Thread.currentThread().getName() + "     ,    ");
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                System.out.println(Thread.currentThread().getName() + "     ");
                writeLock.unlock();
            }
        }
     
        public static void main(String[] args) {
            new Thread(()-> read(),"Thrad1").start();
            new Thread(()-> read(),"Thrad2").start();
            new Thread(()-> write(),"Thrad3").start();
            new Thread(()-> write(),"Thrad4").start();
        }
    }
     
        :
    Thrad1     ,    
    Thrad2     ,    
    Thrad2     
    Thrad1     
    Thrad3     ,    
    Thrad3     
    Thrad4     ,    
    Thrad4     
    읽 기와 쓰기 자물쇠 의 대화 방식:
    읽 기 삽입 정책:
    공평 자물쇠:새치기 불가4
  • 불공평 한 자물쇠:자 물 쇠 를 쓸 때 수시로 새치기 할 수 있 습 니 다.자 물 쇠 를 읽 을 때 대기 열 헤드 노드 에서 만 자 물 쇠 를 쓸 때 새치기 할 수 있 습 니 다.
  • 자 회전 자물쇠 와 차단 자물쇠
    4.567917.현재 스 레 드 를 자전 시 킵 니 다.자전 이 완 료 된 후에 앞 에 동기 화 자원 을 잠 그 는 스 레 드 가 잠 겨 있 으 면 현재 스 레 드 는 막 지 않 고 동기 화 자원 을 직접 가 져 와 스 레 드 전환 비용 을 피 할 수 있 습 니 다.이것 이 바로 자전거 자물쇠 다4.567917.자 물 쇠 를 막 는 것 은 자전 자물쇠 와 반대로 자 물 쇠 를 막 는 것 은 자 물 쇠 를 얻 지 못 한 상황 이 발생 하면 바로 스 레 드 를 막 고 깨 워 진 것 을 알 게 된다.
    자전 단점:
    4.567917.잠 금 이 오래 걸 리 면 자전 하 는 스 레 드 는 프로세서 자원 을 낭비 할 뿐이다4.567917.자전 하 는 과정 에서 cpu 를 계속 소모 하기 때문에 자전 자물쇠 의 시작 비용 은 비관 적 인 자물쇠 보다 낮 지만 자전 하 는 시간 이 증가 함 에 따라 비용 도 선형 으로 증가 했다.
    원리:
    4.567917.자바 1.5 버 전 및 이상 의 병발 프레임 워 크 자바 util.concurrent 의 atmoic 패키지 의 종 류 는 기본적으로 자전 자물쇠 의 실현 이다4
  • AtomicInteger 의 실현:자 회전 자물쇠 의 실현 원 리 는 CAS 이다.AtomicInteger 에서 unsafe 를 호출 하여 자체 증가 작업 을 하 는 소스 코드 중의 do-while 순환 은 자 회전 작업 이다.수정 과정 에서 다른 스 레 드 경쟁 을 만 나 수정 에 성공 하지 못 하면 while 에서 수정 이 성공 할 때 까지 순환 한다.
  • 
    /**
     *   :     
     */
    class SpinLock{
        private AtomicReference<Thread> sign = new AtomicReference<>();
     
        public void lock(){
            Thread currentThread = Thread.currentThread();
            while (!sign.compareAndSet(null,currentThread)){
                System.out.println("      ,    ");
            }
        }
     
        public void unLock(){
            Thread currentThread = Thread.currentThread();
            sign.compareAndSet(currentThread,null);
        }
     
        public static void main(String[] args) {
            SpinLock spinLock = new SpinLock();
            Runnable runnable = new Runnable(){
                @Override
                public void run(){
                    System.out.println(Thread.currentThread().getName()+"       ");
                    spinLock.lock();
                    System.out.println(Thread.currentThread().getName()+"       ");
                    try {
                        Thread.sleep(1);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }finally {
                        spinLock.unLock();
                        System.out.println(Thread.currentThread().getName()+"      ");
                    }
                }
            };
     
            Thread thread1 = new Thread(runnable);
            Thread thread2 = new Thread(runnable);
            thread1.start();
            thread2.start();
        }
    }
     
     
        :
    Thread-0       
    Thread-0       
    Thread-1       
          ,    
          ,    
          ,    
          ,    
          ,    
          ,    
          ,    
          ,    
          ,    
          ,    
          ,    
    Thread-0      
    Thread-1       
    Thread-1      
    사용 필드:
    4.567917.자전 자 물 쇠 는 보통 다 핵 서버 에 사용 되 는데 병발 도가 특별히 높 지 않 은 상황 에서 자 물 쇠 를 막 는 효율 보다 높다4.567917.또한 자 회전 자 물 쇠 는 임계 구역 이 비교적 짧 은 상황 에 적용 된다.그렇지 않 으 면 임계 구역 이 매우 크다(스 레 드 가 자 물 쇠 를 가 져 오 면 오래 후에 방출 된다).그것 도 적당 하지 않다.
    총결산
    자바 의 잠 금 분류 와 사용 방법 에 관 한 이 글 은 여기까지 소개 되 었 습 니 다.더 많은 자바 의 잠 금 사용 내용 은 우리 의 이전 글 을 검색 하거나 아래 의 관련 글 을 계속 조회 하 시기 바 랍 니 다.앞으로 많은 응원 바 랍 니 다!

    좋은 웹페이지 즐겨찾기