這張我們講講多線程之間通信和ThreadGroup!
單線程間通信:
如果服務器端有若干個線程會從隊列中獲取想要的數(shù)據(jù)止邮,進行異步處理捌显,那么這些線程是如何知道隊列中有數(shù)據(jù)呢?
1.一個比較笨的方法-不斷輪詢国瓮,如果隊列中有數(shù)據(jù),那么讀取數(shù)據(jù)并且處理匠楚,如果沒有 再次等待若干時間巍膘,再次輪詢,
2.第二種方法為:通知機制如果隊列中有數(shù)據(jù)芋簿,則通知現(xiàn)場開始工作峡懈,沒有,則通知線程休息与斤。
初始wait 和Notify
舉個栗子
線程之間進行通信肪康,首先實現(xiàn)一個EventQueue,該Queue有三種狀態(tài)撩穿,
1.隊列滿了磷支,最多可容乃多少個Event
2.隊列空,當所有的Event都被處理食寡,沒有在提交Event的時候.
3.有Event但是沒有滿雾狈,有新的Event被提交,但此時沒有上線抵皱。
public class EventQueue {
private final int max ;
static class Event{}
private final LinkedList<Event> eventQueue = new LinkedList<>();
private final static int DEFAULT_MAX_EVENT = 200;
public EventQueue(){
this(DEFAULT_MAX_EVENT);
}
public EventQueue(int max){
this.max = max;
}
private void console(String msg){
System.out.printf("%s :%s \n",Thread.currentThread().getName(),msg);
}
public void put(Event event){
synchronized(eventQueue){
while(eventQueue.size() >= max){
console("隊里滿了!");
try {
eventQueue.wait();
System.out.println("我在wait 方法后面");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
console("事件被提交!");
eventQueue.addLast(event);
eventQueue.notifyAll();
}
}
public Event take(){
synchronized(eventQueue){
while (eventQueue.isEmpty()){
try {
console("當前隊列為空!");
eventQueue.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Event event = eventQueue.removeFirst();
this.eventQueue.notifyAll();
console("這個事件被處理:"+event);
return event;
}
}
}
put(Event event);將當前event添加到LinkList的鏈表中善榛,take();從LinkList拿到頭部的Event辩蛋。
wait和notify方法詳解
wait()方法有三個重載方法。
public final void wait() throws InterruptedException
public final void wait(long timeout) throws InterruptedException
public final void wait(long timeout,int nanos)throws InterruptedException
wait方法的三個重載方法都調用wait(long timeout);這個方法移盆,Object的wait(long timeout)方法會導致當前線程進入阻塞悼院,直到有其他線程調用了Object的notify或者notifyAll方法,或者wait到了一定的時間而自動喚醒。
wait方法必須擁有該對象的Monitor咒循,也就是wait方法必須在同步方法中使用据途。
當前線程執(zhí)行了該對象的wait方法之后,將會放棄該montor的所有權并且進入與對象關聯(lián)的wait set中叙甸,
notify 喚醒正在執(zhí)行該對象wait方法颖医,被喚醒的對象需要重新獲取對該對象所關聯(lián)monitor的lock才能繼續(xù)執(zhí)行。
關于wait和notify的注意事項
1.wait是可中斷的方法蚁署,其他線程是可以調用interrupt是可以將其打斷的便脊。
2.如果線程執(zhí)行了wait方法 ,會加入與之對應的wait set
3.當線程進入wait set之后光戈,notify方法可以進行喚醒,也就是從wait set中彈出來遂赠。
4.必須在同步代碼塊中使用wait 和notify
5.同步代碼的monitor必須與執(zhí)行wait 和notify的方法的對象一致久妆。也就是說那個對象進行同步,就只能用哪個對象進行wait和notify操作跷睦。
wait和sleep的區(qū)別
1.wait和sleep 都會使線程進入阻塞狀態(tài)筷弦。都是可以中斷的,中斷后收到中斷異常
2.wait是Object的方法抑诸,sleep是Thread特有的方法
3.wait必須要在同步代碼塊中使用烂琴,而sleep不需要
4.同步代碼塊中,執(zhí)行sleep方法時蜕乡,并不會釋放monitor的鎖奸绷,而wait方法會釋放。
5.sleep方法如果指定休眠時間层玲,休眠時間到了之后會主動退出阻塞号醉,而wait方法(沒有指定修改時間)則需要被其他線程中斷后才能退出阻塞。
wait set介紹
在虛擬機規(guī)范中存在一個線程休息室(wait set) 的概念辛块,wait set是什么樣的數(shù)據(jù)結構 官方并沒有給出規(guī)范畔派,但是不管怎么樣,當一個線程執(zhí)行了wait方法后润绵,都會進入到與改對象monitor關聯(lián)的wait set中线椰,并且釋放monitor的所有權,一個線程調用該monitor的notify方法之后尘盼,其中一個線程會彈出來憨愉,至于是先進先出烦绳,還是隨機 JVM并沒有 給出規(guī)范。而執(zhí)行notifyAll 則不需要考慮那個線程會被彈出莱衩,因為wait set中的所有wait線程都將被彈出爵嗅。
synchronized關鍵字的缺陷
1.synchronized提供了一種排它機制,某個線程獲取monitor可能會被阻塞笨蚁,而這種阻塞有兩個很明顯的缺陷睹晒,第一,無法控制阻塞時長括细,第二伪很,阻塞不可被中斷。
ThreadGroup 與Thread 介紹
在JAVA程序中奋单,默認情況下锉试,新的線程都會被加入到Main線程所在的group中,main線程的group名字同線程名览濒,如同父子關系一樣,ThreadGroup同樣也存在父子關系呆盖,當創(chuàng)建一個線程的時候,當前線程都會被加入到一個ThreadGroup中贷笛,
創(chuàng)建ThreadGroup
public ThreadGroup(String name)
public ThradGroup(ThreadGroup parent,String name)
方法一:指定了Thread的名字应又,但是該ThreadGroup的父ThreadGroup是創(chuàng)建它的線程所在的ThreadGroup;
方法二:ThreadGroup的構造函數(shù)賦予group名字的同時顯示地指定了父group。
ThreadGroup的基本操作
-activeCount() 用于獲取group中活躍的線程乏苦。這是個預估值株扛,并不能保證100%準確,
-activeGroupCount() 用于獲取group中活躍的字group汇荐,這也是個預估值洞就。
-getName用于獲取group的名字
-getParent()用于獲取group的父group,如果父group不存在掀淘,則會返回null旬蟋。比如System的group就為Null
-list() 該方法沒有返回值,執(zhí)行該方法會將group中所有的活躍線程信息全部輸出到控制臺繁疤,
-setMaxPriority(int priority)指定group的最大優(yōu)先級咖为,最大優(yōu)先級不能超過父group的最大優(yōu)先級,執(zhí)行方法不僅會改變當前group的最大優(yōu)先級稠腊,還會改變子group的最大優(yōu)先級
-interrupt()一個ThreadGroup調用interrupt會導致group中所有active線程都被interrupt,也就是該group中的每一個線程的interrupt標識都被設置了躁染,
-destory() 用于銷毀ThreadGroup,該方法只是針對一個沒有任何active線程的group進行destory標記架忌,調用改方法的直接結果是在父group中將自己移除吞彤。
-daemon(),ThreadGroup也可以調用setDaemon方法,將當前ThreadGroup設置為守護ThreadGroup,如果一個ThradGroup設置為守護ThradGroup,如果該group中沒有任何一個active線程的時候饰恕,該group將自動destory挠羔。