相關(guān)方法:
wait():一旦執(zhí)行此方法,當前線程就進入阻塞狀態(tài),并釋放同步監(jiān)視器。
notify():一旦執(zhí)行此方法,就會喚醒被wait的一個線程,如果有多個線程被wait,就喚醒優(yōu)先級高的那個。
notifyAll():一旦執(zhí)行此方法,就會喚醒所有被wait的線程。
說明:
1.wait(),notify(),notifyAll()三個方法必須使用在同步代碼塊或同步方法中。
2.wait(),notify(),notifyAll()三個方法的調(diào)用者必須是同步代碼塊或同步方法中的同步監(jiān)視器。
否則,會出現(xiàn)IllegalMonitorStateException異常
3.wait(),notify(),notifyAll()三個方法是定義在java.lang.Object類中。
線程通信的例子:使用兩個線程打印1-100.線程1,線程2 交替打印
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
class Number implements Runnable{ private int number = 1 ; @Override public void run() { while ( true ){ synchronized ( this ) { notify(); if (number <= 100 ){ try { Thread.sleep( 10 ); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + ":" + number); number++; try { //使得調(diào)用如下wait()方法的線程進入阻塞狀態(tài) wait(); } catch (InterruptedException e) { e.printStackTrace(); } } else { break ; } } } } } public class CommunicationTest { public static void main(String[] args) { Number number = new Number(); Thread t1 = new Thread(number); Thread t2 = new Thread(number); t1.setName( "線程1" ); t2.setName( "線程2" ); t1.start(); t2.start(); } } |
經(jīng)典例題:生產(chǎn)者/消費者問題
生產(chǎn)者(Productor)將產(chǎn)品交給店員(Clerk),而消費者(Customer)從店員處取走產(chǎn)品店員一次只能持有固定數(shù)量的產(chǎn)品(比如:20),如果生產(chǎn)者試圖生產(chǎn)更多的產(chǎn)品,店員會叫生產(chǎn)者停一下,如果店中有空位放產(chǎn)品了再通知生產(chǎn)者繼續(xù)生產(chǎn),如果店中沒有產(chǎn)品了,店員會告訴消費者等一下,如果店中有產(chǎn)品了再通知消費者來取走產(chǎn)品。
這里可能出現(xiàn)兩個問題:
>生產(chǎn)者比消費者快時,消費者會漏掉一些數(shù)據(jù)沒有取到。
>消費者比生產(chǎn)者塊時,消費者會取相同的數(shù)據(jù)。
分析:
- 是否是多線程問題?是,生產(chǎn)者線程,消費者線程
- 是否有共享數(shù)據(jù)?有,店員(或產(chǎn)品)
- 如何解決線程安全問題?同步機制,有三種方法
- 是否涉及線程的通信?是
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
|
class Clerk{ private int productCount = 0 ; //生產(chǎn)產(chǎn)品 public synchronized void produceProduct() { if (productCount < 20 ){ productCount++; System.out.println(Thread.currentThread().getName() + ":開始生產(chǎn)第" + productCount + "個產(chǎn)品" ); notify(); } else { try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } //消費產(chǎn)品 public synchronized void consumeProduct() { if (productCount > 0 ){ System.out.println(Thread.currentThread().getName() + ":開始消費第" + productCount + "個產(chǎn)品" ); productCount--; notify(); } else { try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } } class Producer extends Thread{ //生產(chǎn)者 private Clerk clerk; public Producer(Clerk clerk){ this .clerk = clerk; } @Override public void run() { System.out.println(getName() + ":開始生產(chǎn)產(chǎn)品....." ); while ( true ){ try { sleep( 10 ); } catch (InterruptedException e) { e.printStackTrace(); } clerk.produceProduct(); } } } class Consumer extends Thread{ //消費者 private Clerk clerk; public Consumer(Clerk clerk){ this .clerk = clerk; } @Override public void run() { System.out.println(getName() + ":開始消費產(chǎn)品....." ); while ( true ){ try { sleep( 10 ); } catch (InterruptedException e) { e.printStackTrace(); } clerk.consumeProduct(); } } } public class ProductTest { public static void main(String[] args) { Clerk clerk = new Clerk(); Producer p1 = new Producer(clerk); p1.setName( "生產(chǎn)者1" ); Consumer c1 = new Consumer(clerk); c1.setName( "消費者1" ); Consumer c2 = new Consumer(clerk); c2.setName( "消費者2" ); p1.start(); c1.start(); c2.start(); } } |
sleep()和wait()的異同?
1.相同點:一旦執(zhí)行方法,都可以使得當前的線程進入阻塞狀態(tài)。
2.不同點:
1)兩個方法聲明的位置不同,Thread類中聲明sleep(),Object類中聲明wait()
2)調(diào)用的要求不同:sleep()可以在任何需要的場景下調(diào)用。wait()必須使用在同步代碼塊或同步方 法中
3)關(guān)于是否釋放同步監(jiān)視器:如果兩個方法都使用在同步代碼塊或同步方法中,sleep()不會釋放 鎖,wait()會釋放鎖
到此這篇關(guān)于Java線程通信中關(guān)于生產(chǎn)者與消費者案例分析的文章就介紹到這了,更多相關(guān)Java線程通信內(nèi)容請搜索服務(wù)器之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持服務(wù)器之家!
原文鏈接:https://blog.csdn.net/weixin_49329785/article/details/119454916