线程的基本协作和生产者消费者
協(xié)作基礎(chǔ)(wait/notify)
Java的根父類是Object,Java在Object類而非Thread類中,定義了一些線程協(xié)作的基本方法,使得每個(gè)對(duì)象都可以調(diào)用這些方法,這些方法有兩類,一類是wait,另一類是notify。
wait方法主要有兩個(gè):
public final void wait() throws InterruptedException public final native void wait(long timeout) throws InterruptedException;一個(gè)帶時(shí)間參數(shù),單位是毫秒,表示最多等待這么長時(shí)間,參數(shù)為0表示無限期等待。一個(gè)不帶時(shí)間參數(shù),表示無限期等待,實(shí)際就是調(diào)用wait(0)。在等待期間都可以被中斷,如果被中斷,會(huì)拋出InterruptedException。
wait實(shí)際上做了什么呢?每個(gè)對(duì)象都有一把鎖和一個(gè)鎖等待隊(duì)列,一個(gè)線程在進(jìn)入synchronized代碼塊時(shí),會(huì)嘗試獲取鎖,獲取不到的話會(huì)把當(dāng)前線程加入等待隊(duì)列中。其實(shí),除了用于鎖的等待隊(duì)列,每個(gè)對(duì)象還有另一個(gè)等待隊(duì)列,表示條件隊(duì)列,該隊(duì)列用于線程間的協(xié)作。調(diào)用wait就會(huì)把當(dāng)前線程放到條件隊(duì)列上并阻塞,表示當(dāng)前線程執(zhí)行不下去了,它需要等待一個(gè)條件,這個(gè)條件它自己改變不了,需要其他線程改變。當(dāng)其他線程改變了條件后,應(yīng)該調(diào)用Object的notify方法:
public final native void notify(); public final native void notifyAll();notify做的事情就是從條件隊(duì)列中選一個(gè)線程,將其從隊(duì)列中移除并喚醒,notifyAll和notify的區(qū)別是,它會(huì)移除條件隊(duì)列中所有的線程并全部喚醒。
wait/notify方法只能在synchronized代碼塊內(nèi)被調(diào)用,如果調(diào)用wait/notify方法時(shí),當(dāng)前線程沒有持有對(duì)象鎖,會(huì)拋出異常java.lang.IllegalMonitorStateException。
wait的具體過程是:
-
- 如果能夠獲得鎖,線程狀態(tài)變?yōu)镽UNNABLE,并從wait調(diào)用中返回
- 否則,該線程加入對(duì)象鎖等待隊(duì)列,線程狀態(tài)變?yōu)锽LOCKED,只有在獲得鎖后才會(huì)從wait調(diào)用中返回
線程從wait調(diào)用中返回后,不代表其等待的條件就一定成立了,它需要重新檢查其等待的條件,一般的調(diào)用模式是:
synchronized (obj) {while (條件不成立)obj.wait();... // 條件滿足后的操作 }?
生產(chǎn)者/消費(fèi)者模式
下面來看一個(gè)生產(chǎn)者和消費(fèi)者的例子:
/*** @author 沉默哥* */ public class MyProducerConsumerDemo {static class GoodsQueue {private int size;private Queue<String> que = new ArrayDeque<String>();public GoodsQueue(int size) {// 維護(hù)一個(gè)有界隊(duì)列,傳入隊(duì)列的最大容量super();this.size = size;}public synchronized void put(String e) throws InterruptedException {while (que.size() == size) {System.out.println("隊(duì)列已滿,生產(chǎn)者等待");wait();}que.add(e);System.out.println("生產(chǎn)者生產(chǎn):" + e);notify();}public synchronized String take() throws InterruptedException {while (que.size() == 0) {System.out.println("隊(duì)列為空,消費(fèi)者等待");wait();}String e = que.poll();System.out.println("消費(fèi)者消費(fèi)" + e);notify();return e;}}static class Producer extends Thread {GoodsQueue que;Random rad = new Random();public Producer(GoodsQueue que) {super();this.que = que;}@Overridepublic void run() {int i = 0;try {while (true) {String e = String.valueOf(i);que.put(e);i++;Thread.sleep(rad.nextInt(1000));// 生產(chǎn)者休息準(zhǔn)備下一次生產(chǎn) }} catch (InterruptedException e1) {}}}static class Consumer extends Thread {GoodsQueue que;Random rad = new Random();public Consumer(GoodsQueue que) {super();this.que = que;}@Overridepublic void run() {try {while (true) {que.take();Thread.sleep(rad.nextInt(1000));// 消費(fèi)者休息準(zhǔn)備下一次消費(fèi) }} catch (InterruptedException e) {}}}public static void main(String[] args) throws InterruptedException {GoodsQueue que = new GoodsQueue(1);Producer pro = new Producer(que);Consumer con = new Consumer(que);con.start();Thread.sleep(500);pro.start();} }?
?
轉(zhuǎn)載于:https://www.cnblogs.com/JackPn/p/9426366.html
總結(jié)
以上是生活随笔為你收集整理的线程的基本协作和生产者消费者的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ARM指令集详解(超详细!带实例!)
- 下一篇: Flask 框架app = Flask(