자바 스 레 드 wait () 와 notify () 의 용법 (깨 어 난 스 레 드 가 동기 코드 블록 을 다시 실행 하 는 지, 아니면 기다 리 는 곳 에서 계속 실행 하 는 지)

8388 단어 Java
자바 스 레 드 wait () 와 notify () 의 용법 (깨 어 난 스 레 드 가 동기 코드 블록 을 다시 실행 하 는 지, 아니면 기다 리 는 곳 에서 계속 실행 하 는 지)  
2013-09-24 22:15:58|  분류: 자바 | 제 보 | 상호 구독 하 다.
우 리 는 먼저 이 두 가지 방법의 정 의 를 살 펴 보 자.
      wait()   현재 스 레 드 를 기다 리 게 합 니 다. 다른 스 레 드 가 이 대상 의 notify () 방법 이나 notify All () 방법 을 호출 하기 전에 현재 스 레 드 를 기다 리 게 합 니 다.
     notify()  이 동기 모니터 에서 기다 리 는 단일 스 레 드 를 깨 웁 니 다. 이 동기 모니터 에서 여러 스 레 드 가 기다 리 면 그 중 하 나 를 깨 웁 니 다.
 
현재 시스템 이 특수 한 요구 가 있다 고 가정 하면 시스템 은 예금자 와 인출 자 에 게 끊임없이 중복 저금 을 요구 하고 돈 을 찾 는 동작 을 요구한다. 또한 예금자 가 지 정 된 계좌 에 입금 할 때마다 돈 을 찾 는 사람 은 즉시 이 돈 을 찾 아야 한다. 예금자 가 두 번 연속 저금 하 는 것 을 허락 하지 않 고 전자 가 두 번 돈 을 찾 는 것 도 허락 하지 않 는 다.
실 현 된 코드 는 다음 과 같다.
이 프로그램 은 account 류 를 통 해 draw 와 depost 두 가지 방법 을 제공 합 니 다. 각각 해당 계 정의 인출 과 저금 에 대해 Public class account {를 조작 합 니 다. private String accountNo;  private double balance;  //표지 계좌 에 예금 의 표지 가 있 는 지 여부 private boolean flag = false;
 public Account(){}
 public Account(String accountNo , double balance)  {   this.accountNo = accountNo;   this.balance = balance;  }
 public void setAccountNo(String accountNo)  {   this.accountNo = accountNo;  }  public String getAccountNo()  {    return this.accountNo;  }
 public double getBalance()  {    return this.balance;  }  public synchronized void draw(double drawAmount)  {   try   {    //만약 flag 가 가짜 라면 계좌 에 아직 돈 을 저금 하 는 사람 이 없다 는 것 을 나타 내 면 돈 을 찾 는 방법 이 막힌다.   if (!flag)    {     wait();    }    else    {     //집행 인출    System.out.println(Thread.currentThread().getName() +       "인출:" +  drawAmount);     balance -= drawAmount;     System. out. println ("계 정 잔액 은:" + balance);    //표지 계 정 에 예금 이 있 는 지 여 부 를 false 로 설정 합 니 다.    flag = false;     //다른 스 레 드 깨 우기    notifyAll();    }   }   catch (InterruptedException ex)   {    ex.printStackTrace();   }  }  public synchronized void deposit(double depositAmount)  {   try   {    //만약 flag 가 사실 이 라면, 계좌 에 이미 돈 을 저금 한 사람 이 있다 는 것 을 나타 내 면, 저금 방법 이 막힌다.   if (flag)    {     wait();    }    else    {     //예금 을 집행 하 다    System.out.println(Thread.currentThread().getName() +       "예금:" +  depositAmount);     balance += depositAmount;     System. out. println ("계 정 잔액 은:" + balance);    //계좌 에 예금 이 있 는 지 여 부 를 표시 하 는 깃발 을 true 로 설정 합 니 다.    flag = true;     //다른 스 레 드 깨 우기    notifyAll();    }   }   catch (InterruptedException ex)   {    ex.printStackTrace();   }  }
 public int hashCode()  {   return accountNo.hashCode();  }  public boolean equals(Object obj)  {   if (obj != null && obj.getClass() == Account.class)   {    Account target = (Account)obj;    return target.getAccountNo().equals(accountNo);   }   return false;  } }
프로그램 에서 입금 자 스 레 드 는 백 번 순환 하여 중복 저금 을 하고 전 자 를 찾 으 면 백 번 순환 하여 돈 을 찾 습 니 다. 입금 자 스 레 드, 인출 이 스 레 드 는 각각 account 대상 의 deposit, draw 방법 으로 이 루어 집 니 다.
public class DrawThread extends Thread {  //아 날로 그 사용자 계 정 private Account account;  //현재 인출 라인 에서 원 하 는 금액 private double drawAmount;
 public DrawThread(String name , Account account ,    double drawAmount)  {   super(name);   this.account = account;   this.drawAmount = drawAmount;  }
 //돈 인출 작업 100 회 반복 public void run()  {   for (int i = 0 ; i < 100 ; i++ )   {    account.draw(drawAmount);   }  } }
public class DepositThread extends Thread {  //아 날로 그 사용자 계 정 private Account account;  //현재 인출 라인 에서 원 하 는 예금 의 금액 private double depositAmount;
 public DepositThread(String name , Account account ,    double depositAmount)  {   super(name);   this.account = account;   this.depositAmount = depositAmount;  }
 //예금 조작 100 회 반복 public void run()  {   for (int i = 0 ; i < 100 ; i++ )   {    account.deposit(depositAmount);   }    } }
메 인 프로그램 은 임의의 여분의 예금 과 인출 라인 을 시작 할 수 있다. 모든 인출 라인 은 반드시 예금 라인 이 돈 을 저금 한 후에 야 아래로 실행 할 수 있 고 예금 라인 도 반드시 인출 라인 이 돈 을 인출 한 후에 야 아래로 실행 할 수 있다. 메 인 프로그램 코드 는 다음 과 같다.
public class TestDraw {  public static void main(String[] args)   {   //계 정 만 들 기  Account acct = new Account("1234567" , 0);   new DrawThread ("인출 자", acct, 800). start ();  new depositThread ("예금자 갑", acct, 800). start ();  }
}
지금 우 리 는 본론 으로 들 어 갔다. 한 라인 이 깨 어 난 후에 실행 되 기 시작 하 는 곳 을 기다 리 고 있 을 때 이 문 제 는 나 를 한동안 곤 혹 스 럽 게 했다.
다음은 다음 방법 안의 코드 를 고 쳐 보 겠 습 니 다.
public synchronized void draw(double drawAmount)  {   try   {    //만약 flag 가 가짜 라면 계좌 에 아직 돈 을 저금 하 는 사람 이 없다 는 것 을 나타 내 면 돈 을 찾 는 방법 이 막힌다.   if (!flag)    {     wait();    }    else    {     //집행 인출    System.out.println(Thread.currentThread().getName() +       "인출:" +  drawAmount);     balance -= drawAmount;     System. out. println ("계 정 잔액 은:" + balance);    //표지 계 정 에 예금 이 있 는 지 여 부 를 false 로 설정 합 니 다.    flag = false;     //다른 스 레 드 깨 우기    notifyAll();    }   }   catch (InterruptedException ex)   {    ex.printStackTrace();   }  }
그것 을 고 쳐 쓰기;
주의 하 십시오. 저 는 위의 코드 를 바탕 으로 전역 변 수 를 추 가 했 습 니 다: Public  int   in = 0 ;
public synchronized void draw(double drawAmount)    {  
System. out. println ("동기 화 된 void draw 에 들 어 갑 니 다");     try   { //만약 flag 가 가짜 라면 계좌 에 아직 돈 을 저금 하 는 사람 이 없다 는 것 을 나타 내 면 돈 을 찾 는 방법 이 막힌다.   if (!flag)    {//AtomicInteger        in++;
    //현재 스 레 드 이름 바 꾸 기     Thread. currentThread (). setName ("인출 자 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA     System.out.println(Thread.currentThread().getName() +        "차단");     wait();    }    else    {        //집행 인출    System.out.println(Thread.currentThread().getName() +       "인출:" +  drawAmount);     balance -= drawAmount;     System. out. println ("돈 을 찾 는 데 성 공 했 습 니 다 ---------------------- 계좌 잔액 은 = = = = = = = = = = = = = = = = = = = = = =" + balance);    //표지 계 정 에 예금 이 있 는 지 여 부 를 false 로 설정 합 니 다.    flag = false;     //다른 스 레 드 깨 우기    System.out.println("                    ======인출 하여 다른 라인 을 일깨우다                         ");          notifyAll();    }   System. out. println ("이 인민공화국 = = = = = = = = = = = = = = 이 인민공화국 = = = = = = 이 인민공화국");  }   catch (InterruptedException ex)   {    ex.printStackTrace();   }  }  지금 우 리 는 프로그램의 운행 을 상상 해 봅 시다. 우 리 는 마치 인출 자 스 레 드 를 시작 한 것 같 습 니 다. 즉, 우리 계좌 에 아직 전이 없 을 때 돈 을 찾 으 러 갑 니 다. 당신 은 그 은행 이 틀림없이 하지 않 을 것 이 라 고 상상 합 니 다. 그래서 그것 은 대기 에 들 어 갈 것 입 니 다. 대기 에 들 어간 후에 우 리 는 그것 을 이름 을 바 꾸 었 습 니 다. (끝 에 숫자 를 붙 였 습 니 다. 이 숫자 는 대기 에 들 어 가 는 횟수 를 대표 합 니 다)대기 자 예금 스 레 드 에서 상 태 를 바 꾸 고 대기 자 는 notfy () 로 깨 워 달라 고 합 니 다. 지금 우 리 는 두 가지 실행 상황 이 있다 고 가정 합 니 다.
(1): 깨 어 난 후에 이 동기 코드 블록 에서 새로 실 행 됩 니 다. 이 때 콘 솔 은 "synchronized 에 들 어 갑 니 다."    void draw
     else () 블록 안에 있 습 니 다. 즉, 지금 돈 을 찾 을 수 있 을 것 입 니 다. 그리고 콘 솔 수출 을 볼 수 있 습 니 다.
     =====이 인민공화국
(2): 기다 리 는 곳 (wait () 방법 을 계속 실행 하고 if 와 else 가 상대 적 으로 서 있 기 때문에 else 에 들 어가 지 않 기 때문에 스 레 드 는
     2 차 진입 라인 은 빈손으로 나 간 것 이기 때문에 콘 솔 출력 을 볼 수 있 습 니 다.
     =====이 인민공화국  void draw "그리고 돈 찾기 작업 을 하고 있 습 니 다.
 
사실은 두 번 째 상황 과 같다.
그래서 결론 은 다음 과 같다.
 
자바 대상 중 두 가지 풀 이 있 습 니 다.  작은 못  대기 탱크 ---------------- wait (), notify (), notifyAll ()  한 스 레 드 가 대상 의 wait 방법 을 호출 하면 이 스 레 드 는 대상 의 대기 탱크 에 들 어 갑 니 다 (또한 잠 금 을 풀 었 습 니 다).  만약 미래의 어느 순간, 다른 스 레 드 가 같은 대상 의 notify 방법 이나 notify All 방법 을 호출 했다 면,  그러면 대기 탱크 의 스 레 드 가 불 려 와 대상 의 잠 금 탱크 에 들 어가 대상 의 자 물 쇠 를 얻 습 니 다.  잠 금 에 성공 하면 이 스 레 드 는 wait 방법 이후 의 경 로 를 따라 계속 실 행 됩 니 다. wait 방법 을 따라 다른 답 을 찾 는 것 을 주의 하 십시오.
wait              。
    ,          wait  ,            ,
  ,         notifyAll()(           )  notify()(      ,              ),             。
             ,                  ,         ,         ,        wait  ,           。

       。

추궁 하 다
                      ,             wait   

대답 하 다.
     ,     ,         ,    cpu   ,       。
        “          wait   ”。

추궁 하 다
         ,        ,             ,             ,                  ,         ,         ,      (  wait      )                     wait   

대답 하 다.
wait  ,wait           。
    ,       :
            ,       wait()     ,        ,        :
1.         。
2.     。
3.    wait()     。
4.    notify()     。

추궁 하 다
      
            :1、          2、     

좋은 웹페이지 즐겨찾기