Java 執行緒狀態和等待喚醒機制和執行緒池的實現
1.概念
執行緒一共有6中狀態,相互之間可以互相轉換。
等待喚醒案例(執行緒之間的通訊)
實現:
等待喚醒案例:執行緒之間的通訊
建立一個顧客執行緒(消費者):告知老闆要的包子的種類和數量,呼叫wait方法,放棄cpu的執行,進入到WAITING狀態(無限等待)
建立一個老闆執行緒(生產者):花了5秒做包子,做好包子之後,呼叫notify方法,喚醒顧客吃包子
注意:
顧客和老闆執行緒必須使用同步程式碼塊包裹起來,保證等待和喚醒只能有一個在執行
同步使用的鎖物件必須保證唯一
只有鎖物件才能呼叫wait和notify方法
Obejct類中的方法
void wait()
在其他執行緒呼叫此物件的 notify() 方法或 notifyAll() 方法前,導致當前執行緒等待。
喚醒在此物件監視器上等待的單個執行緒。
會繼續執行wait方法之後的程式碼
進入到TimeWaiting(計時等待)有兩種方式
1.使用sleep(long m)方法,在毫秒值結束之後,執行緒睡醒進入到Runnable/Blocked狀態
2.使用wait(long m)方法,wait方法如果在毫秒值結束之後,還沒有被notify喚醒,就會自動醒來,執行緒睡醒進入到Runnable/Blocked狀態
喚醒的方法:
void notify() 喚醒在此物件監視器上等待的單個執行緒。
void notifyAll() 喚醒在此物件監視器上等待的所有執行緒。
public static void main(String[] args) { //建立鎖物件,保證唯一 final Object obj = new Object(); // 建立一個顧客執行緒(消費者) new Thread(){ @Override public void run() { //一直等著買包子 while(true){ //保證等待和喚醒的執行緒只能有一個執行,需要使用同步技術 synchronized (obj){ System.out.println("顧客1告知老闆要的包子的種類和數量"); //呼叫wait方法,進入到WAITING狀態(無限等待) try { obj.wait(); } catch (InterruptedException e) { e.printStackTrace(); } //喚醒之後執行的程式碼 System.out.println("包子已經做好了,顧客1開吃!"); System.out.println("---------------------------------------"); } } } }.start(); // 建立一個顧客執行緒(消費者) new Thread(){ @Override public void run() { //一直等著買包子 while(true){ //保證等待和喚醒的執行緒只能有一個執行,需要使用同步技術 synchronized (obj){ System.out.println("顧客2告知老闆要的包子的種類和數量"); //呼叫wait方法,顧客2開吃!"); System.out.println("---------------------------------------"); } } } }.start(); //建立一個老闆執行緒(生產者) new Thread(){ @Override public void run() { //一直做包子 while (true){ //花了5秒做包子 try { Thread.sleep(5000);//花5秒鐘做包子 } catch (InterruptedException e) { e.printStackTrace(); } //保證等待和喚醒的執行緒只能有一個執行,需要使用同步技術 synchronized (obj){ System.out.println("老闆5秒鐘之後做好包子,告知顧客,可以吃包子了"); //做好包子之後,喚醒顧客吃包子 //obj.notify();//如果有多個等待執行緒,隨機喚醒一個 obj.notifyAll();//喚醒所有等待的執行緒 } } } }.start(); }
2.等待喚醒機制
就是在一個執行緒進行了規定操作後,就進入等待狀態(wait()), 等待其他執行緒執行完他們的指定程式碼過後 再將其喚醒notify();在有多個執行緒進行等待時, 如果需要,可以使用 notifyAll()來喚醒所有的等待執行緒。wait/notify 就是執行緒間的一種協作機制。
等待喚醒中的方法 :
- wait:執行緒不再活動,不再參與排程,進入 wait set 中,因此不會浪費 CPU 資源,也不會去競爭鎖了,這時的執行緒狀態即是 WAITING。它還要等著別的執行緒執行一個特別的動作,也即是“通知(notify)”在這個物件上等待的執行緒從wait set 中釋放出來,重新進入到排程佇列(ready queue)中
- notify:則選取所通知物件的 wait set 中的一個執行緒釋放;例如,餐館有空位置後,等候就餐最久的顧客最先入座。
- notifyAll:則釋放所通知物件的 wait set 上的全部執行緒。
3.執行緒池
執行緒池其實就是一個容納多個執行緒的容器,其中的執行緒可以反覆使用,省去了頻繁建立執行緒物件的操作,無需反覆建立執行緒而消耗過多資源。
Java裡面執行緒池的頂級介面是java.util.concurrent.Executor
,但是嚴格意義上講Executor
並不是一個執行緒池,而只是一個執行執行緒的工具。真正的執行緒池介面是java.util.concurrent.ExecutorService
。 要配置一個執行緒池是比較複雜的,尤其是對於執行緒池的原理不是很清楚的情況下,很有可能配置的執行緒池不是較優的,因此在java.util.concurrent.Executors
執行緒工廠類裡面提供了一些靜態工廠,生成一些常用的執行緒池。官方建議使用Executors工程類來建立執行緒池物件。
使用:
執行緒池:JDK1.5之後提供的
java.util.concurrent.Executors:執行緒池的工廠類,用來生成執行緒池
Executors類中的靜態方法:
static ExecutorService newFixedThreadPool(int nThreads) 建立一個可重用固定執行緒數的執行緒池
引數:
int nThreads:建立執行緒池中包含的執行緒數量
返回值:
ExecutorService介面,返回的是ExecutorService介面的實現類物件,我們可以使用ExecutorService介面接收(面向介面程式設計)
java.util.concurrent.ExecutorService:執行緒池介面
用來從執行緒池中獲取執行緒,呼叫start方法,執行執行緒任務
submit(Runnable task) 提交一個 Runnable 任務用於執行
關閉/銷燬執行緒池的方法
void shutdown()
執行緒池的使用步驟:
1.使用執行緒池的工廠類Executors裡邊提供的靜態方法newFixedThreadPool生產一個指定執行緒數量的執行緒池
2.建立一個類,實現Runnable介面,重寫run方法,設定執行緒任務
3.呼叫ExecutorService中的方法submit,傳遞執行緒任務(實現類),開啟執行緒,執行run方法
4.呼叫ExecutorService中的方法shutdown銷燬執行緒池(不建議執行)
例子:
public class RunnableImpl implements Runnable{ @Override public void run() { System.out.println(Thread.currentThread().getName()+"建立了一個新的執行緒執行"); } } public static void main(String[] args) { //1.使用執行緒池的工廠類Executors裡邊提供的靜態方法newFixedThreadPool生產一個指定執行緒數量的執行緒池 ExecutorService es = Executors.newFixedThreadPool(2); //3.呼叫ExecutorService中的方法submit,執行run方法 es.submit(new RunnableImpl());//pool-1-thread-1建立了一個新的執行緒執行 //執行緒池會一直開啟,使用完了執行緒,會自動把執行緒歸還給執行緒池,執行緒可以繼續使用 es.submit(new RunnableImpl());//pool-1-thread-1建立了一個新的執行緒執行 es.submit(new RunnableImpl());//pool-1-thread-2建立了一個新的執行緒執行 //4.呼叫ExecutorService中的方法shutdown銷燬執行緒池(不建議執行) es.shutdown(); es.submit(new RunnableImpl());//拋異常,執行緒池都沒有了,就不能獲取執行緒了 }
到此這篇關於Java 執行緒狀態和等待喚醒機制和執行緒池的實現的文章就介紹到這了,更多相關Java 執行緒狀態和等待喚醒機制 內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!