java多線程之wait(),notify(),notifyAll()的詳解分析
更新時(shí)間:2013年06月04日 15:20:19 作者:
本篇文章是對(duì)java多線程 wait(),notify(),notifyAll()進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
wait(),notify(),notifyAll()不屬于Thread類,而是屬于Object基礎(chǔ)類,也就是說每個(gè)對(duì)象都有wait(),notify(),notifyAll()的功能.因?yàn)槊總€(gè)對(duì)象都有鎖,鎖是每個(gè)對(duì)象的基礎(chǔ),當(dāng)然操作鎖的方法也是最基礎(chǔ)了。
wait導(dǎo)致當(dāng)前的線程等待,直到其他線程調(diào)用此對(duì)象的 notify() 方法或 notifyAll() 方法,或被其他線程中斷。wait只能由持有對(duì)像鎖的線程來調(diào)用。
notify喚醒在此對(duì)象監(jiān)視器上等待的單個(gè)線程。如果所有線程都在此對(duì)象上等待,則會(huì)選擇喚醒其中一個(gè)線程(隨機(jī))。直到當(dāng)前的線程放棄此對(duì)象上的鎖,才能繼續(xù)執(zhí)行被喚醒的線程。同Wait方法一樣,notify只能由持有對(duì)像鎖的線程來調(diào)用.notifyall也一樣,不同的是notifyall會(huì)喚配所有在此對(duì)象鎖上等待的線程。
"只能由持有對(duì)像鎖的線程來調(diào)用"說明wait方法與notify方法必須在同步塊內(nèi)執(zhí)行,即synchronized(obj)之內(nèi).再者synchronized代碼塊內(nèi)沒有鎖是寸步不行的,所以線程要繼續(xù)執(zhí)行必須獲得鎖。相輔相成。
看一個(gè)很經(jīng)典的例子(生產(chǎn)者與消費(fèi)者):
首先是消費(fèi)者線程類:
import java.util.List;
public class Consume implements Runnable {
private List container = null;
private int count;
public Consume(List lst) {
this.container = lst;
}
public void run() {
while (true) {
synchronized (container) {
if (container.size() == 0) {
try {
container.wait();// 容器為空,放棄鎖,等待生產(chǎn)
} catch (InterruptedException e) {
e.printStackTrace();
}
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
container.remove(0);
container.notify();
System.out.println("我吃了" + (++count) + "個(gè)");
}
}
}
}
接下來是生產(chǎn)者線程類:
import java.util.List;
public class Product implements Runnable {
private List container = null;
private int count;
public Product(List lst) {
this.container = lst;
}
public void run() {
while (true) {
synchronized (container) {
if (container.size() > MultiThread.MAX) {
// 如果容器超過了最大值,就不要在生產(chǎn)了,等待消費(fèi)
try {
container.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
container.add(new Object());
container.notify();
System.out.println("我生產(chǎn)了" + (++count) + "個(gè)");
}
}
}
}
最后是測試類:
import java.util.ArrayList;
import java.util.List;
public class MultiThread {
private List container = new ArrayList();
public final static int MAX = 5;
public static void main(String args[]) {
MultiThread m = new MultiThread();
new Thread(new Consume(m.getContainer())).start();
new Thread(new Product(m.getContainer())).start();
}
public List getContainer() {
return container;
}
public void setContainer(List container) {
this.container = container;
}
}
運(yùn)行結(jié)果如下所示:
我生產(chǎn)了1個(gè)
我吃了1個(gè)
我生產(chǎn)了2個(gè)
我生產(chǎn)了3個(gè)
我生產(chǎn)了4個(gè)
我生產(chǎn)了5個(gè)
我生產(chǎn)了6個(gè)
我生產(chǎn)了7個(gè)
我吃了2個(gè)
我生產(chǎn)了8個(gè)
我吃了3個(gè)
我生產(chǎn)了9個(gè)
我吃了4個(gè)
我吃了5個(gè)
我吃了6個(gè)
我吃了7個(gè)
我吃了8個(gè)
我生產(chǎn)了10個(gè)
我生產(chǎn)了11個(gè)
我吃了9個(gè)
我生產(chǎn)了12個(gè)
我吃了10個(gè)
......
wait導(dǎo)致當(dāng)前的線程等待,直到其他線程調(diào)用此對(duì)象的 notify() 方法或 notifyAll() 方法,或被其他線程中斷。wait只能由持有對(duì)像鎖的線程來調(diào)用。
notify喚醒在此對(duì)象監(jiān)視器上等待的單個(gè)線程。如果所有線程都在此對(duì)象上等待,則會(huì)選擇喚醒其中一個(gè)線程(隨機(jī))。直到當(dāng)前的線程放棄此對(duì)象上的鎖,才能繼續(xù)執(zhí)行被喚醒的線程。同Wait方法一樣,notify只能由持有對(duì)像鎖的線程來調(diào)用.notifyall也一樣,不同的是notifyall會(huì)喚配所有在此對(duì)象鎖上等待的線程。
"只能由持有對(duì)像鎖的線程來調(diào)用"說明wait方法與notify方法必須在同步塊內(nèi)執(zhí)行,即synchronized(obj)之內(nèi).再者synchronized代碼塊內(nèi)沒有鎖是寸步不行的,所以線程要繼續(xù)執(zhí)行必須獲得鎖。相輔相成。
看一個(gè)很經(jīng)典的例子(生產(chǎn)者與消費(fèi)者):
首先是消費(fèi)者線程類:
復(fù)制代碼 代碼如下:
import java.util.List;
public class Consume implements Runnable {
private List container = null;
private int count;
public Consume(List lst) {
this.container = lst;
}
public void run() {
while (true) {
synchronized (container) {
if (container.size() == 0) {
try {
container.wait();// 容器為空,放棄鎖,等待生產(chǎn)
} catch (InterruptedException e) {
e.printStackTrace();
}
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
container.remove(0);
container.notify();
System.out.println("我吃了" + (++count) + "個(gè)");
}
}
}
}
接下來是生產(chǎn)者線程類:
復(fù)制代碼 代碼如下:
import java.util.List;
public class Product implements Runnable {
private List container = null;
private int count;
public Product(List lst) {
this.container = lst;
}
public void run() {
while (true) {
synchronized (container) {
if (container.size() > MultiThread.MAX) {
// 如果容器超過了最大值,就不要在生產(chǎn)了,等待消費(fèi)
try {
container.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
container.add(new Object());
container.notify();
System.out.println("我生產(chǎn)了" + (++count) + "個(gè)");
}
}
}
}
最后是測試類:
復(fù)制代碼 代碼如下:
import java.util.ArrayList;
import java.util.List;
public class MultiThread {
private List container = new ArrayList();
public final static int MAX = 5;
public static void main(String args[]) {
MultiThread m = new MultiThread();
new Thread(new Consume(m.getContainer())).start();
new Thread(new Product(m.getContainer())).start();
}
public List getContainer() {
return container;
}
public void setContainer(List container) {
this.container = container;
}
}
運(yùn)行結(jié)果如下所示:
復(fù)制代碼 代碼如下:
我生產(chǎn)了1個(gè)
我吃了1個(gè)
我生產(chǎn)了2個(gè)
我生產(chǎn)了3個(gè)
我生產(chǎn)了4個(gè)
我生產(chǎn)了5個(gè)
我生產(chǎn)了6個(gè)
我生產(chǎn)了7個(gè)
我吃了2個(gè)
我生產(chǎn)了8個(gè)
我吃了3個(gè)
我生產(chǎn)了9個(gè)
我吃了4個(gè)
我吃了5個(gè)
我吃了6個(gè)
我吃了7個(gè)
我吃了8個(gè)
我生產(chǎn)了10個(gè)
我生產(chǎn)了11個(gè)
我吃了9個(gè)
我生產(chǎn)了12個(gè)
我吃了10個(gè)
......
您可能感興趣的文章:
相關(guān)文章
Java8新特性之精簡的JRE詳解_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
這篇文章主要介紹了Java8新特性之精簡的JRE詳解的相關(guān)資料,需要的朋友可以參考下2017-06-06幾種JAVA細(xì)粒度鎖的實(shí)現(xiàn)方式
這篇文章主要為大家詳細(xì)介紹了幾種JAVA細(xì)粒度鎖的實(shí)現(xiàn)方式,感興趣的小伙伴們可以參考一下2016-05-05詳解IDEA多module項(xiàng)目maven依賴的一些說明
這篇文章主要介紹了詳解IDEA多module項(xiàng)目maven依賴的一些說明,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-10-10SpringBoot項(xiàng)目URL訪問異常的問題處理
這篇文章主要介紹了SpringBoot項(xiàng)目URL訪問異常的問題處理方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-07-07使用@Valid+BindingResult進(jìn)行controller參數(shù)校驗(yàn)方式
這篇文章主要介紹了使用@Valid+BindingResult進(jìn)行controller參數(shù)校驗(yàn)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-12-12