1、等待和通知機制(wait、notify)
wait()方法
使當前執行代碼的線程進入等待的狀態,該方法是Object類的方法,使當前線程進入預執行隊列,使用wait()方法前,必須拿到對象級別的鎖,即只能在同步方法裏執行,執行wait方法之後會釋放鎖,線程進入了等待的狀態。
notify方法
和wait方法一樣,同樣要拿到對象級別的鎖,也就是隻能在同步方法內執行。notify的作用是通知調用wait方法進入等待的線程,恢復執行。調用notify方法之後,不會立即釋放鎖,程wait狀態的線程也不會立即拿到鎖,只有調用notify方法的線程執行完同步方法之後,纔會釋放鎖。釋放鎖完之後,當執行wait方法的線程拿到鎖之後,就會恢復執行。
notifyAll方法
如果有多個線程調用了wait方法,只調用notify通知,則是隨機通知某一個線程恢復執行,如果想要通知全部線程,則調用notifyAll方法
wait和sleep的區別
相同點:wait和sleep都會使當前線程暫停執行
不同點:
1、wait是Object類的方法,而sleep是Thread的方法
2、wait的執行必須要拿到對象級別的鎖,也就是必須在同步方法裏執行,而sleep不是必須的。
3、wait執行完之後,會立即釋放鎖,使得當前線程暫停執行。而sleep方法雖然是使得當前線程暫停執行,不會釋放鎖,也就是說當sleep執行在同步方法裏的時候,會使得當前線程進入阻塞的狀態。
2、生產者和消費者模式(實現線程之間的通信)
生產者
package com.company;
import java.util.Date;
/**
* 生產者
*/
public class ProductThread extends Thread {
private Goods goods;
public ProductThread(Goods goods) {
this.goods = goods;
}
@Override
public void run() {
super.run();
while (true) {
productGoods();
}
}
/**
* 生產商品
*/
private void productGoods() {
synchronized (goods) {
try {
//如果商品還沒被消費,則先等被消費
if (goods.getName() != null) {
goods.wait();
}
//如果已經被消費了,則生產商品
goods.setName(new Date().getTime() + "");
System.out.println("生產商品:" + goods.getName());
//通知消費
goods.notify();
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
消費者
package com.company;
/**
* 消費者
*/
public class ConsumerThread extends Thread {
//消費商品
private Goods goods;
public ConsumerThread(Goods goods) {
this.goods = goods;
}
@Override
public void run() {
super.run();
while (true) {
cosumerGoods();
}
}
/**
* 消費商品
*/
private void cosumerGoods() {
synchronized (goods) {
try {
//如果商品還沒被生產,則先等生產
if (goods.getName() == null) {
goods.wait();
}
System.out.println("消費商品:" + goods.getName());
//如果商品已經生產了,直接消費商品
goods.setName(null);
//通知生產
goods.notify();
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
商品
package com.company;
/**
* 商品類
*/
public class Goods {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
測試
package com.company;
public class MyMain {
public static void main(String[] args) {
Goods goods = new Goods();
ProductThread productThread = new ProductThread(goods);
ConsumerThread consumerThread = new ConsumerThread(goods);
productThread.start();
consumerThread.start();
}
}
結果
生產商品:1607925851349
消費商品:1607925851349
生產商品:1607925853350
消費商品:1607925853350
生產商品:1607925855351
消費商品:1607925855351
生產商品:1607925857351
消費商品:1607925857351
生產者消費者模型分析
- 生產者生產商品,當發現商品還沒有被消費的時候,則進入等待狀態。如果商品已經被消費沒有了,則生產商品,通知消費者消費。
- 消費者消費商品,當發現商品還沒有被生產的時候,則進入等待狀態。如果商品已經被生產了,則消費商品,通知生產者繼續生產商品。
- 生產者和消費者都需要對商品進行加鎖,防止線程安全問題。