자바 대기 각성 메커니즘 원리 및 사용

이 글 은 주로 자바 대기 각성 메커니즘 의 원리 와 사용 을 간단하게 이해 하 는 것 을 소개 하 였 으 며,글 에 서 는 예시 코드 를 통 해 매우 상세 하 게 소개 하 였 으 며,여러분 의 학습 이나 업무 에 대해 어느 정도 참고 학습 가 치 를 가지 고 있 으 며,필요 한 친 구 는 참고 하 실 수 있 습 니 다.
이것 은 심혈 을 기울 인 구덩이 메 우기 노트 입 니 다.자바 를 독학 한 몇 년 동안 새로운 기술 을 계속 배 웠 습 니 다.걸 어 오 면서 자신 이 구 덩이 를 많이 밟 았 다 는 것 을 알 게 되 었 고 채 워 진 구 덩이 는 손 에 꼽 을 수 있 습 니 다.갑자기 가끔 은 정말 몇 년 의 업무 경험 이 문제 가 아니 라 10 년 동안 일 해도 열심히 공부 하지 않 은 것 이 10 년 의 큰 구덩이 에 불과 하 다 는 것 을 알 게 되 었 다.
다 중 스 레 드 를 처음 접 했 을 때 이 물건 을 기다 리 거나 깨 울 줄 알 았 습 니 다.demo 라 고 쓰 면 다 시 는 보지 못 했 습 니 다.그것 이 도대체 무엇 인지,아니면 어떤 문 제 를 해결 할 수 있 는 지 에 대해 서 는 대부분의 사람들 이 저 와 마찬가지 로 애매모호 할 것 입 니 다.이번에 필 자 는 당신 을 데 리 고 기다 림/깨 우기 체 제 를 이해 하려 고 합 니 다.본 고 를 읽 으 면 다음 과 같은 몇 가 지 를 얻 을 것 입 니 다.
  • 순환 대기 가 어떤 문 제 를 가 져 올 지
  • 대기 각성 메커니즘 으로 순환 대기 최적화
  • 깨 우기 메커니즘 에서 무시 되 는 세부 사항 을 기다린다
  • 질문
    만약 에 오늘 월급 을 주 려 고 한다 면 강 사장 은 좋 은 음식 을 먹 으 러 가 야 한다.전체 식사 절 차 는 다음 과 같은 몇 가지 절차 로 나 눌 수 있다.
  • 주문
  • 창구 에서 외식 대기
  • 식사
  • 
     public static void main(String[] args) {
       //       
        AtomicBoolean hasBun = new AtomicBoolean();
        
        //      
        new Thread(() -> {
          try {
            //             
            while (true) {
              if (hasBun.get()) {
                System.out.println("  :           ...");
                Thread.sleep(3000);
              } else {
                System.out.println("  :     ,       ...");
                Thread.sleep(1000);
                System.out.println("  :     ....");
                hasBun.set(true);
              }
            }
          } catch (InterruptedException e) {
            e.printStackTrace();
          }
        }).start();
    
    
        new Thread(() -> {
          System.out.println("  :     ...");
          try {
            //             
            while (!hasBun.get()) {
              System.out.println("  :        ~");
              Thread.sleep(3000);
            }
            System.out.println("  :       ....");
          } catch (InterruptedException e) {
            e.printStackTrace();
          }
        }).start();
      }

    위의 코드 에 큰 문제 가 존재 한다.바로 사장 이 만두 가 있 는 지 계속 검사 해 야 하고 고객 은 일정 시간 간격 으로 사장 을 보 러 가 야 한다.이것 은 분명 합 리 적 이지 않다.이것 이 바로 전형 적 인 순환 대기 문제 이다.

    이런 문제 의 코드 에는 보통 다음 과 같은 모델 이 있다.
    
      while (     ) {
        Thread.sleep(3000);
      }
      doSomething();
    컴퓨터 에 대응 하면 하나의 문제 가 드 러 났 다.폴 링 체 제 를 통 해 조건 이 성립 되 는 지 계속 검 측 하고 폴 링 시간 이 너무 적 으 면 CPU 자원 을 낭비 할 수 있 으 며 간격 이 너무 크 면 원 하 는 자원 을 신속하게 얻 지 못 할 수도 있다.
    둘째,대기/깨 우기 메커니즘
    순환 대기 CPU 소모 및 정보 신속 성 문 제 를 해결 하기 위해 자바 에 서 는 대기 각성 체 제 를 제공 합 니 다.쉽게 말 하면 주동 에서 수 동적 으로 바 뀌 고 조건 이 성립 될 때 해당 하 는 스 레 드 를 주동 적 으로 통지 하 는 것 이지 스 레 드 자체 에 문의 하 게 하 는 것 이 아니다.
    2.1 기본 개념
    대기/깨 우기 메커니즘 은 대기 알림(필 자 는 알림 이 아 닌 깨 우기)이 라 고도 부른다.스 레 드 A 가 대상 O 의 wait()방법 을 호출 하여 대기 상태 에 들 어 갔 고 다른 스 레 드 는 O 의 notify()또는 notify All()방법 을 호출 했다.스 레 드 A 가 통 지 를 받 은 후에 대상 O 의 wait()방법 으로 돌아 와 후속 작업 을 수행 했다.
    항소 과정 은 대상 O 를 통 해 스 레 드 A 와 스 레 드 B 간 에 통신 을 하고 스 레 드 에서 대상 O 의 wait()방법 을 호출 한 후 스 레 드 가 오랫동안 차단 상태 에 들 어 갔 으 며 다른 스 레 드 에서 대상 O 가 notify()또는 notify All 방법 을 호출 할 때 해당 하 는 차단 스 레 드 를 깨 웁 니 다.
    2.2 기본 API
    시스템 에 대한 방법 을 기다 리 거나 깨 울 때 임의의 자바 대상 이 갖 추고 있 습 니 다.이 방법 들 은 모든 자바 대상 의 초 클래스 Object 에 정의 되 어 있 기 때 문 입 니 다.
    notify:대상 에서 기다 리 는 스 레 드 를 wait()방법 으로 되 돌려 주 고 되 돌아 오 는 전제 에서 대상 의 자 물 쇠 를 가 져 옵 니 다.
    notify All:이 대상 을 기다 리 는 모든 스 레 드 를 알려 줍 니 다.
    wait:이 방법 을 사용 하 는 스 레 드 는 차단 대기 상태 에 들 어 갑 니 다.다른 스 레 드 의 알림 을 기다 리 거나 중단 되 어야 돌아 갑 니 다.wait 방법 을 사용 하면 대상 의 자 물 쇠 를 풀 수 있 습 니 다.
    wait(long):한 동안 깨 어 나 지 않 으 면 시간 을 초과 하여 자동 으로 돌아 갑 니 다.단 위 는 밀리초 입 니 다.
    2.3 대기 각성 메커니즘 으로 순환 대기 최적화
    
    public static void main(String[] args) {
      //       
        AtomicBoolean hasBun = new AtomicBoolean();
        //    
        Object lockObject = new Object();
    
        //      
        new Thread(() -> {
          try {
            while (true) {
              synchronized (lockObject) {
                if (hasBun.get()) {
                  System.out.println("  :     ,       ");
                  lockObject.wait(); 
                } else {
                  System.out.println("  :     ,       ...");
                  Thread.sleep(3000);
                  System.out.println("  :     ....");
                  hasBun.set(true);
                  //        
                  lockObject.notifyAll();
                }
              }
            }
          } catch (InterruptedException e) {
            e.printStackTrace();
          }
        }).start();
    
    
        new Thread(() -> {
          System.out.println("  :     ...");
          try {
            synchronized (lockObject) {
              if (!hasBun.get()) {
                System.out.println("  :        ,     cruder      ");
                lockObject.wait(); 
              } else {
                System.out.println("  :       ,      ....");
                hasBun.set(false);
                lockObject.notifyAll();
                System.out.println("  :           ,         ~~");
              }
            }
          } catch (InterruptedException e) {
            e.printStackTrace();
          }
        }).start();
     }

    상기 절 차 는 폴 링 검사 의 조작 을 줄 이 고 스 레 드 가 wait()방법 을 호출 한 후에 자 물 쇠 를 방출 하여 CPU 자원 을 소모 하지 않 고 프로그램의 성능 을 향상 시 켰 다.
    3.깨 우기 메커니즘 의 기본 패 러 다 임 을 기다린다.
    대기,깨 우 는 것 은 스 레 드 간 통신 의 수단 중 하나 로 여러 스 레 드 가 같은 데이터 소스 를 조작 하 는 것 을 조율 하 는 데 사용 된다.실제 응용 에서 순환 대기 문 제 를 최적화 시 키 고 대기 자 와 통지 자 를 대상 으로 다음 과 같은 전형 적 인 범례 를 추출 할 수 있다.
    주의해 야 할 것 은 대기 자가 실행 하 는 논리 에서 while 순환 으로 대기 조건 을 판단 해 야 한 다 는 것 입 니 다.notify/notify All 방법 을 실행 할 때 대기 스 레 드 를 wait 방법 에서 되 돌려 주 는 것 이지 임계 구역 에 다시 들 어 가 는 것 이 아 닙 니 다.
    
    /**
     *         
     * 1.       
     * 2.     ,       ,     wait  ,          
     * 3.             
     */
    synchronized(  ){
      while(     ){
          .wait()
      }
      doSomething();
    }
    /**
     * !!         
     * 1.       
     * 2.     
     * 3.   (  )         
     */
    synchronized(  ){
          
        .notify();
    }
    이 프로 그래 밍 패 러 다 임 은 전형 적 인 통지 자 와 대기 자 를 대상 으로 하 는 것 이 고 가끔 은 쌍방 이 이중 신분 을 가 질 수 있 으 며 대기 자 는 통지 자 이 더 라 도 우리 가 상기 한 사례 와 같다.
    4.notify/notifyAll 잠 금 해제 하지 않 음
    이 문 제 는 엔지니어 의 절반 이 모 르 고 wait()방법 을 실행 하면 자물쇠 가 자동 으로 풀 려 날 것 이 라 고 믿 습 니 다.그러나 notify()방법 을 실행 한 후 자 물 쇠 는 풀 리 지 않 고 notify()방법 이 있 는 synchronized 코드 블록 을 실행 해 야 풀 립 니 다.이 점 은 매우 중요 하고 많은 엔지니어 들 이 소홀히 하기 쉬 운 부분 이다.
    
    lockObject.notifyAll();
    System.out.println("  :           ,         ~~");
    사례 코드 에서 일부러 notify All 로 설정 한 다음 에 인쇄 합 니 다.위의 그림 에서 의 결과 도 우리 의 묘 사 를 입증 했다.관심 이 있 는 파트너 는 사례 코드 를 실행 할 수 있다.
    5.대기,각성 은 먼저 자 물 쇠 를 가 져 와 야 합 니 다.
    대기,깨 우기 프로 그래 밍 모드 에서 wait,notify,notify All 방법 은 직접 호출 되 지 않 습 니 다.잠 금 을 가 져 온 임계 구역 에서 실행 해 야 합 니 다.
    그리고 같은 자물쇠 에 기다 리 는 스 레 드 만 깨 울 수 있 습 니 다.
    스 레 드 가 wait 방법 을 호출 할 때 대기 열 에 가입 합 니 다.notify 를 실행 할 때 대기 열 에 있 는 첫 번 째 대기 스 레 드(대기 시간 이 가장 긴 스 레 드)를 깨 우 고 notify All 을 호출 할 때 대기 스 레 드 에 있 는 모든 대기 스 레 드 를 깨 웁 니 다.

    6,sleep 자 물 쇠 를 풀 지 않 고 wait 방출\#
    대기 깨 우기 메커니즘 으로 순환 기다 림 을 최적화 하 는 과정 에서 중요 한 특징 은 원래 의 sleep()방법 을 wait()방법 으로 대체 하 는 것 이다.그들의 가장 큰 차이 점 은 wait 방법 은 자 물 쇠 를 방출 하 는 것 이 고 sleep 는 그렇지 않다 는 것 이다.그 밖 에 중요 한 차이 점 이 있다.sleep 는 Thread 의 방법 으로 임 의적 으로 실행 할 수 있다.wait 는 Object 대상 의 방법 으로 synchronized 코드 블록 에서 실행 해 야 합 니 다.
    이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.

    좋은 웹페이지 즐겨찾기