線程的概念是什麼?線程之間是如何通訊的? java
線程是進程中的一個執行單元,同一個進程中的各個線程對應於一組CPU指令、一組CPU寄存器以及一堆棧。進程原本就具備動態的含義,然而實質上是經過線程來執行體現的,從這個意義上說,Windows中進程的動態性意義已經不是很明顯了,只算是給程序所佔的資源劃定一個範圍而已,真正具備動態性意義的是線程。 多線程
其實,Java提供了3個很是重要的方法來巧妙地解決線程間的通訊問題。這3個方法分別是:wait()、notify()和notifyAll()。它們都是Object類的最終方法,所以每個類都默認擁有它們。 dom
雖然全部的類都默認擁有這3個方法,可是隻有在synchronized關鍵字做用的範圍內,而且是同一個同步問題中搭配使用這3個方法時纔有實際的意義。 this
這些方法在Object類中聲明的語法格式以下所示: spa
final void wait() throws InterruptedExceptionfinal void notify()final void notifyAll() 線程
其中,調用wait()方法可使調用該方法的線程釋放共享資源的鎖,而後從運行態退出,進入等待隊列,直到被再次喚醒。而調用notify()方法能夠喚醒等待隊列中第一個等待同一共享資源的線程,並使該線程退出等待隊列,進入可運行態。調用notifyAll()方法可使全部正在等待隊列中等待同一共享資源的線程從等待狀態退出,進入可運行狀態,此時,優先級最高的那個線程最早執行。顯然,利用這些方法就沒必要再循環檢測共享資源的狀態,而是在須要的時候直接喚醒等待隊列中的線程就能夠了。這樣不但節省了寶貴的CPU資源,也提升了程序的效率。 隊列
因爲wait()方法在聲明的時候被聲明爲拋出InterruptedException異常,所以,在調用wait()方法時,須要將它放入try…catch代碼塊中。此外,使用該方法時還須要把它放到一個同步代碼段中,不然會出現以下異常: 進程
"java.lang.IllegalMonitorStateException: current thread not owner" 資源
這些方法是否是就能夠實現線程間的通訊了呢?下面將經過多線程同步的模型:生產者和消費者問題來講明怎樣經過程序解決多線程間的通訊問題。 get
案例:線程的通訊
案例說明
下面這個程序演示了多個線程之間進行通訊的具體實現過程。程序中用到了4個類,其中ShareData類用來定義共享數據和同步方法。在同步方法中調用了wait()方法和notify()方法,並經過一個信號量來實現線程間的消息傳遞。
實現過程
//CommunicationDemo.java 描述:生產者和消費者之間的消息傳遞過程
class ShareData{
private char c;
private boolean isProduced = false; // 信號量
public synchronized void putShareChar(char c) // 同步方法putShareChar()
{
if (isProduced){ // 若是產品還未消費,則生產者等待
try{
wait(); // 生產者等待
}catch(InterruptedException e){
e.printStackTrace();
}
}
this.c = c;
isProduced = true; // 標記已經生產
notify(); // 通知消費者已經生產,能夠消費
}
public synchronized char getShareChar() // 同步方法getShareChar()
{
if (!isProduced) // 若是產品還未生產,則消費者等待
{
try{
wait(); // 消費者等待
}catch(InterruptedException e){
e.printStackTrace();
}
}
isProduced = false; // 標記已經消費
notify(); // 通知須要生產
return this.c;
}
}
class Producer extends Thread // 生產者線程
{
private ShareData s;
Producer(ShareData s){
this.s = s;
}
public void run(){
for (char ch = ''A''; ch <= ''D''; ch++){
try{
Thread.sleep((int)(Math.random()*3000));
}catch(InterruptedException e){
e.printStackTrace();
}
s.putShareChar(ch); // 將產品放入倉庫
System.out.println(ch + " is produced by Producer.");
}
}
}
class Consumer extends Thread // 消費者線程
{
private ShareData s;
Consumer(ShareData s){
this.s = s;
}
public void run(){
char ch;
do{
try{
Thread.sleep((int)(Math.random()*3000));
}catch(InterruptedException e){
e.printStackTrace();
}
ch = s.getShareChar(); // 從倉庫中取出產品
System.out.println(ch + " is consumed by Consumer. ");
}while (ch != ''D'');
}
}
class CommunicationDemo{
public static void main(String[] args){
ShareData s = new ShareData();
new Consumer(s).start();
new Producer(s).start();
}
}