1. 程式人生 > >多執行緒之執行緒通訊wait和notify的使用

多執行緒之執行緒通訊wait和notify的使用

使用wait和notify方法實現執行緒之間的通訊,注意,這兩個方法是Object類的方法,也就是說Java為所有的物件都提供的這兩個方法。

1 wait和notify必須配合synchronized關鍵字使用。

2 wait方法釋放鎖,notify方法不釋放鎖。

3 還要注意一點 就是涉及到執行緒之間的通訊,就肯定會用到validate修飾。

案例:
t1執行緒向集合中不斷新增元素,當集合中元素個數為5的時候,就向t2執行緒發出通知,(當集合元素個數不等於5時候,t2執行緒處於等待狀態),然後t2向下執行,丟擲異常。

package com.wuk.Demo;

import java.util.ArrayList;
import
java.util.List; /** * wait和notify的使用 * * @author Administrator * */ public class MyThread004 { private static volatile List list=new ArrayList(); public void add() { list.add("wuk"); } public int size() { return list.size(); } public static void main
(String[] args) { MyThread004 list1=new MyThread004(); Object obj=new Object(); Thread t1=new Thread(new Runnable() { @Override public void run() { synchronized (obj) { System.out.println("t1執行緒啟動。。。。"); for
(int i=0;i<10;i++) { list1.add(); System.out.println("當前執行緒"+Thread.currentThread().getName()+"添加了一個元素"); try { Thread.sleep(500); if(list1.size()==5) { System.out.println("已經發出通知。。"); obj.notify(); } } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } },"t1"); Thread t2=new Thread (new Runnable() { @Override public void run() { synchronized (obj) { System.out.println("t2啟動。。。"); if(list1.size()!=5) { try { obj.wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } System.out.println("當前執行緒:" + Thread.currentThread().getName() + "收到通知執行緒停止.."); throw new RuntimeException(); } } },"t2"); t2.start(); t1.start(); } }

列印結果:

t2啟動。。。
t1執行緒啟動。。。。
當前執行緒t1添加了一個元素
當前執行緒t1添加了一個元素
當前執行緒t1添加了一個元素
當前執行緒t1添加了一個元素
當前執行緒t1添加了一個元素
已經發出通知。。
當前執行緒t1添加了一個元素
當前執行緒t1添加了一個元素
當前執行緒t1添加了一個元素
當前執行緒t1添加了一個元素
當前執行緒t1添加了一個元素
當前執行緒:t2收到通知執行緒停止..
Exception in thread "t2" java.lang.RuntimeException
    at com.wuk.Demo.MyThread004$2.run(MyThread004.java:79)
    at java.lang.Thread.run(Unknown Source)

分析:
首先啟動t2執行緒,使得t2執行緒處於等待狀態,然後當集合等於5的時候,t1向t2執行緒發出通知,但是並不會釋放鎖,所以當t1執行完畢後,t2執行緒才會向下執行。

分析幾種情況:
(1) 有人說 validate不是可以實現執行緒之間的可見性嗎,那麼我就不需要t1通知,當t2發現集合元素是5了就會往下執行?
去掉obj.notify(); 結果是:

t2啟動。。。
t1執行緒啟動。。。。
當前執行緒t1添加了一個元素
當前執行緒t1添加了一個元素
當前執行緒t1添加了一個元素
當前執行緒t1添加了一個元素
當前執行緒t1添加了一個元素
已經發出通知。。
當前執行緒t1添加了一個元素
當前執行緒t1添加了一個元素
當前執行緒t1添加了一個元素
當前執行緒t1添加了一個元素
當前執行緒t1添加了一個元素

分析:
因為當t2執行了wait()方法,就會處於等待狀態,如果不去喚醒他,他就會一直等待下去。

(2)如果我們先讓t1執行會是什麼結果?

t1執行緒啟動。。。。
當前執行緒t1添加了一個元素
當前執行緒t1添加了一個元素
當前執行緒t1添加了一個元素
當前執行緒t1添加了一個元素
當前執行緒t1添加了一個元素
已經發出通知。。
當前執行緒t1添加了一個元素
當前執行緒t1添加了一個元素
當前執行緒t1添加了一個元素
當前執行緒t1添加了一個元素
當前執行緒t1添加了一個元素
t2啟動。。。

分析:
因為notify不釋放鎖,如果t1先執行,就會先擁有鎖,那麼只有等到t1執行完畢以後,t2才會有機會執行,這時候集合長度早都不是5了,所以就會一直等待下去。