자바 스 레 드 통신 및 스 레 드 허위 각성 지식 총화

6841 단어 Java스 레 드
스 레 드 통신
스 레 드 가 내부 에서 실 행 될 때 스 레 드 스케줄 은 일정한 투명 성 을 가지 고 프로그램 은 스 레 드 의 교대 집행 을 제어 할 수 없습니다.그러나 자바 자 체 는 스 레 드 의 조화 로 운 운행 을 보장 하 는 메커니즘 을 제공 했다.
현재 시스템 에 두 개의 라인 이 있다 고 가정 하면 각각 예금 과 인출 을 대표 한다.돈 을 저금 하면 바로 꺼 내 서 지 정 된 계좌 로 옮긴다.이것 은 스 레 드 간 의 협력 과 관련 되 어 있 습 니 다.Object 류 가 제공 하 는 wait(),notify(),notify All()세 가지 방법 을 사용 합 니 다.Thread 류 에 속 하지 않 고 Object 에 속 합 니 다.이 세 가지 방법 은 모니터 대상 에서 호출 해 야 합 니 다.
  • synchronized 수식 방법 은 이러한 기본 인 스 턴 스(this)가 동기 모니터 이기 때문에 동기 화 방법 에서 직접 호출 할 수 있 습 니 다
  • synchronized 수식 동기 코드 블록,동기 모니터 는 synchronized 괄호 안의 대상 이 므 로 이 대상 을 사용 하여 호출 해 야 합 니 다
  • 세 가지 방법 은 다음 과 같다.
    wait():현재 스 레 드 대기,현재 대상 잠 금 해제,다른 스 레 드 가 notify 또는 notify All 을 사용 하여 이 스 레 드 를 깨 울 때 까지 CPU 를 양보 합 니 다4.567917.notify():이 동기 모니터 에서 기다 리 는 단일 스 레 드 를 깨 우 고 여러 스 레 드 가 존재 하면 무 작위 로 하 나 를 깨 웁 니 다.notify 를 실행 하면 바로 자 물 쇠 를 풀 지 않 습 니 다.synchronized 코드 블록 을 완전히 종료 하거나 도중에 wait 를 만 나 야 wait 상태의 스 레 드 가 이 대상 의 자 물 쇠 를 쟁취 할 수 있 습 니 다4.567917.notify All():이 동기 모니터 의 모든 스 레 드 를 깨 웁 니 다지금 은 두 가지 동기 화 방법 으로 각각 돈 을 저금 하고 돈 을 찾 는 것 을 대표 한다.
    4.567917.잔액 이 0 일 때 저금 절차 에 들 어가 저금 작업 을 한 후에 돈 을 찾 는 스 레 드 를 깨 웁 니 다
  • 잔액 이 0 일 때 돈 을 찾 는 절차 에 들 어가 면 num==0 을 발견 하고 차단 상태 에 들 어가 깨 어 날 때 까지 기다린다
  • 
    /**
         *     
         *
         * @throws InterruptedException
         */
        public synchronized void increase() throws InterruptedException {
            //     1,       ,    。      
            if (num == 1) {
                this.wait();
            }
            //       
            num++;
            System.out.println(Thread.currentThread().getName() + ":num=" + num);
            //       
            this.notifyAll();
        }
     
        /**
         *     
         *
         * @throws InterruptedException
         */
        public synchronized void decrease() throws InterruptedException {
            //     0,       ,    。      
            if (num == 0) {
                this.wait();
            }
            num--;
            System.out.println(Thread.currentThread().getName() + ":num=" + num);
            this.notifyAll();
        }
    
    호출 방법:
    
    private int num = 0;
     
        public static void main(String[] args) {
            Test test = new Test();
     
            new Thread(() -> {
                for (int i = 0; i < 10; i++) {
                    try {
                        test.increase();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }, "  ").start();
     
            new Thread(() -> {
                for (int i = 0; i < 10; i++) {
                    try {
                        test.decrease();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }, "  ").start();
        }
    
    결 과 는 아무 문제 가 없 었 다. 

    스 레 드 거짓 각성
    이 같은 스 레 드 통신 은 별 문제 가 없 는 것 처럼 보이 지만,이때 예금 과 돈 을 찾 는 사람 수 를 각각 1 씩 늘 리 고 운행 결 과 를 보면 된다.
    
    private int num = 0;
     
        public static void main(String[] args) {
            Test test = new Test();
     
            new Thread(() -> {
                for (int i = 0; i < 10; i++) {
                    try {
                        test.increase();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }, "  1").start();
     
            new Thread(() -> {
                for (int i = 0; i < 10; i++) {
                    try {
                        test.decrease();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }, "  1").start();
     
            new Thread(() -> {
                for (int i = 0; i < 10; i++) {
                    try {
                        test.increase();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }, "  2").start();
     
            new Thread(() -> {
                for (int i = 0; i < 10; i++) {
                    try {
                        test.decrease();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }, "  2").start();
        }
    
    생 긴 결 과 는 이미 최초의 것 이 아니 라 0 과 1 만 있 었 다.

    이 결 과 를 초래 한 원인 은 바로 스 레 드 간 의 허위 각성 이다.
    현재 각각 여러 개의 인출 과 예금 라인 이 있 기 때문이다.만약 에 그 중의 한 저금 스 레 드 가 실 행 된 후에 wait 를 사용 하여 동기 모니터 를 잠 그 면 나머지 여러 개의 인출 스 레 드 는 동시에 깨 어 날 것 이다.이때 잔액 은 1 이 고 10 개가 동시에 돈 을 찾 으 면 잔액 은-9 로 변 하여 결과 가 잘못 될 것 이다.
    따라서,매번 스 레 드 가 wait 에서 깨 어 날 때마다,깨 우기 조건 에 부합 되 는 지 다시 테스트 해 야 하 며,부합 되 지 않 으 면 계속 기 다 려 야 합 니 다.
    여러 스 레 드 가 동시에 깨 어 나 서 if(xxxx){wait();}처 if 판단 은 한 번 만 실 행 됩 니 다.현재 깨 어 난 스 레 드 가 왔 을 때 if 가 판단 되 었 기 때문에 wait 뒤의 구문 에서 계속 실 행 됩 니 다.따라서 if 를 while 로 바 꾸 면 이 문 제 를 해결 할 수 있 습 니 다.다음 에 깨 어 난 스 레 드 가 왔 습 니 다.while 다시 판단 해 보 니 깨 어 난 스 레 드 가 잠 겨 있 습 니 다.따라서 이 거짓 으로 깨 어 난 스 레 드 는 자 물 쇠 를 계속 기다 릴 것 이다.
    
     /**
         *     
         *
         * @throws InterruptedException
         */
        public synchronized void increase() throws InterruptedException {
            while (num == 1) {//                       ,   while
                this.wait();
            }
            num++;
            System.out.println(Thread.currentThread().getName() + ":num=" + num);
            this.notifyAll();
        }
     
        /**
         *     
         *
         * @throws InterruptedException
         */
        public synchronized void decrease() throws InterruptedException {
            while (num == 0) {
                this.wait();
            }
            num--;
            System.out.println(Thread.currentThread().getName() + ":num=" + num);
            this.notifyAll();
        }
    
    다시 실행,결과 정상:

    자바 스 레 드 통신 및 스 레 드 허위 깨 우기 지식 총화 에 관 한 이 글 은 여기까지 소개 되 었 습 니 다.더 많은 자바 스 레 드 통신 및 스 레 드 허위 깨 우기 내용 은 우리 의 이전 글 을 검색 하거나 아래 의 관련 글 을 계속 조회 하 시기 바 랍 니 다.앞으로 많은 지원 바 랍 니 다!

    좋은 웹페이지 즐겨찾기