자바 스 레 드 wait () 와 notify () 의 용법 (깨 어 난 스 레 드 가 동기 코드 블록 을 다시 실행 하 는 지, 아니면 기다 리 는 곳 에서 계속 실행 하 는 지)
8388 단어 Java
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、
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
JPA + QueryDSL 계층형 댓글, 대댓글 구현(2)이번엔 전편에 이어서 계층형 댓글, 대댓글을 다시 리팩토링해볼 예정이다. 이전 게시글에서는 계층형 댓글, 대댓글을 구현은 되었지만 N+1 문제가 있었다. 이번에는 그 N+1 문제를 해결해 볼 것이다. 위의 로직은 이...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.