------<ahref="http://www.itheima.com" target="blank">Java培訓、Android培訓、iOS培訓、.Net培訓</a>、期待與您交流! -------
黑馬程式猿——12,多執行緒(2)
//執行緒之間的通訊
//就是多個執行緒操作同一個資源,操作動作不同
//舉一個樣例:一堆資源(名字,性別),一個執行緒輸入,一個執行緒輸出列印
class Person
{
String name;
String sex;
}
class Shuru implements Runnable
{
private Person p;
Shuru( Person p )
{
this.p=p;
}
public void run()
{
int x= 0;
while(true)//特別說明:由於 while (true)這句話的關係。最後要按Ctrl+c按鍵才停下虛擬機器,否則會耗費非常多資源)
{
if(x==0)
{
p.name="張三";
p.sex="男性";
}
else
{
p.name="李四";
p.sex="女性";
}
x=(x+1)%2;
}
}
}
class Shuchu implements Runnable
{
private Person p;
Shuchu( Person p )
{
this.p=p;
}
public void run()
{
while(true)
{
System.out.println(p.name+"-----"+p.sex);
}
}
}
class Xctx
{
public static void main(String[] args)
{
Person p=new Person();
Shuru b1=new Shuru(p);
Shuchu b2=new Shuchu(p);
Thread c1=new Thread(b1);
Thread c2=new Thread(b2);
c1.start();
c2.start();
System.out.println("HelloWorld!");
}
}
/*
依照一般的思路。準確的列印應該是張三相應男性,李四相應女性的
但是編譯執行的結果例如以下。出了問題:
Hello World!
李四-----男性
李四-----男性
李四-----女性
李四-----男性
張三-----女性
張三-----女性
李四-----男性
李四-----男性
張三-----男性
張三-----女性
張三-----男性
張三-----男性
李四-----男性
張三-----男性
李四-----女性
李四-----男性
張三-----男性
李四-----女性
張三-----女性
李四-----女性
李四-----男性
出問題的解決辦法是:輸入執行緒在輸入資訊的同一時候輸出執行緒也在列印,
那麼非常有可能在輸入資訊輸入到一半的時候。就被輸出執行緒列印出去了。
那麼列印出去的就是部分更新資料部分舊資料,這就相應不上了
*/
——————分析——————
//為了解決這樣的問題,我們還是能夠用同步程式碼塊來解決
/*
原理就是輸入執行緒與輸出執行緒都是對同一個物件操作。僅僅只是操作過程不一樣
那麼使用同步程式碼塊,讓兩個使用同一個鎖,這樣就限制了在某一個時刻僅僅能夠有一個執行緒對物件進行操作
等這個執行緒操作完之後下一個執行緒才幹夠對物件進行操作
確保了列印出來的物件資訊的更新是完整
*/
class Person
{
String name;
String sex;
static Object obj=new Object();
}
class Shuru implements Runnable
{
private Person p;
Shuru( Person p )
{
this.p=p;
}
public void run()
{
int x= 0;
while(true)//特別說明:由於 while (true)這句話的關係,最後要按Ctrl+c按鍵才停下虛擬機器。否則會耗費非常多資源)
{
synchronized(Person.obj)//用的鎖是obj
{
if(x==0)
{
p.name="張三";
p.sex="男性";
}
else
{
p.name="李四";
p.sex="女性";
}
x=(x+1)%2;
}
}
}
}
class Shuchu implements Runnable
{
private Person p;
Shuchu( Person p )
{
this.p=p;
}
public void run()
{
while(true)
{
synchronized(Person.obj)//用的鎖是obj
{
System.out.println(p.name+"-----"+p.sex);
}
}
}
}
class Xctx2
{
public static void main(String[] args)
{
Person p=new Person();
Shuru b1=new Shuru(p);
Shuchu b2=new Shuchu(p);
Thread c1=new Thread(b1);
Thread c2=new Thread(b2);
c1.start();
c2.start();
System.out.println("HelloWorld!");
}
}
——————分析——————
</pre><pre name="code" class="java">//執行緒通訊中的等待喚醒機制的樣例
/*
等待喚醒機制,簡單的說法就是
用一個標示(通常是Boolean型的變數)
true標記輸入執行緒操作,而false標記輸出執行緒操作
輸入執行緒操作時候,輸出執行緒凍結狀態
輸出執行緒操作時候。輸入執行緒凍結狀態
這樣來保證輸出結果的準確性
這就須要用到wait()和notify() 或者是notifyAll()
*/
class Person
{
String name;
String sex;
static Object obj=new Object();
boolean bs=true;//設定一個標示
}
class Shuru implements Runnable
{
private Person p;
Shuru( Person p )
{
this.p=p;//接收一個Person類的物件,就指向該物件。該寫法更加方便
}
public void run()
{
int x= 0;
while(true)
//特別說明:由於 while (true)這句話的關係,最後要按Ctrl+c按鍵才停下虛擬機器。否則會耗費非常多資源)
{
synchronized(Person.obj)//用的鎖是obj
{
if(!p.bs)
{
try{Person.obj.wait();}catch(Exception e){}
}
//wait()方法能夠凍結執行緒,該方法是定義在Object類的
/*
這裡為什麼不直接用wait()呢?
由於wait()方法會丟擲一個異常所以要用try...catch
為什麼這裡還要在wait前面加上Person.obj這個鎖呢?
由於這樣的寫法:鎖.wait(); -----表示持有該鎖的執行緒要陷入沉睡。
也是由於這個原因,wait()方法必須在同步中才幹夠用,而notify()
和notifyAll()也是由於以上原因在同步中才幹夠用。
其寫法也是: 鎖.notify();或者是 鎖.notifyAll();
*/
if(x==0)
{
p.name="張三";
p.sex="男性";
}
else
{
p.name="李四";
p.sex="女性";
}
x=(x+1)%2;
Person.obj.notify();
/*
陷入沉睡的執行緒都會被扔進執行緒池
notify()方法功能是喚醒在線上程池中頭一個沉睡的執行緒
而notifyAll()方法則是喚醒全部沉睡的執行緒
*/
p.bs=false;
}
}
}
}
class Shuchu implements Runnable
{
private Person p;
Shuchu( Person p )
{
this.p=p;
}
public void run()
{
while(true)
{
synchronized(Person.obj)//用的鎖是obj
{
if(p.bs)
{
try{Person.obj.wait();} catch(Exception e){}
}
System.out.println(p.name+"-----"+p.sex);
Person.obj.notify();
p.bs=true;
}
}
}
}
class Xctx3
{
public static void main(String[] args)
{
Person p=new Person();
Shuru b1=new Shuru(p);
Shuchu b2=new Shuchu(p);
Thread c1=new Thread(b1);
Thread c2=new Thread(b2);
c1.start();
c2.start();
System.out.println("HelloWorld!");
}
}
/*
以上程式編譯執行結果是:
Hello World!
張三-----男性
李四-----女性
張三-----男性
李四-----女性
張三-----男性
李四-----女性
張三-----男性
李四-----女性
張三-----男性
李四-----女性
張三-----男性
李四-----女性
張三-----男性
李四-----女性
*/
補充:對於非靜態的synchronized方法,其鎖默覺得this
對於靜態的synchronized方法。其鎖預設:為該方法所在類的類名.class
對於同步程式碼塊,其鎖就是括號內的東西。
——————切割線————————
//下面是程式碼優化之後的程式,更加簡潔明瞭
class Person
{
private String name;
private String sex;
private boolean bs=true;//設定一個標示
public synchronized void set( String name,String sex )//寫入資料的方法
{
if(!bs)
{
try{this.wait();}catch(Exception e){}
}
this.name=name;
this.sex=sex;
bs=false;
this.notify();
}
public synchronized void out()//列印資料的方法
{
if(bs)
{
try{this.wait();}catch(Exception e){}
}
System.out.println("輸出的是----"+name+"---"+sex);
bs=true;
this.notify();
}
}
class Shuru implements Runnable
{
private Person p;
Shuru( Person p )
{
this.p=p;
}
public void run()
{
int x= 0;
while(true)//特別說明:由於 while (true)這句話的關係,最後要按Ctrl+c按鍵才停下虛擬機器。否則會耗費非常多資源)
{
if(x==0)
p.set("張三","男性");
else
p.set("李四","女性");
x=(x+1)%2;
}
}
}
class Shuchu implements Runnable
{
private Person p;
Shuchu( Person p )
{
this.p=p;
}
public void run()
{
while(true)
{
p.out();
}
}
}
class Xctx4
{
public static void main(String[] args)
{
Person p=new Person();
newThread(new Shuru(p)).start();
new Thread(new Shuchu(p)).start();
System.out.println("HelloWorld!");
/*
Shuru b1=new Shuru(p);
Shuchu b2=new Shuchu(p);
Thread c1=new Thread(b1);
Thread c2=new Thread(b2);
c1.start();
c2.start();
System.out.println("HelloWorld!");
*/
}
}
————————切割線——————
/*
多執行緒的常見生活樣例
有多個生產者生產食品,有多個消費者消化食品
每生產一個食品就消費一個食品
*/
class Shipin
{
private int sp=0;
private boolean f=true;
public synchronized void shengchang( )
{
while(true)
{
while(f==false)//注意這裡用的是while所以每次執行緒從凍結狀態醒來都要檢查一次f是否是false
try{this.wait();} catch(Exception e){}
sp++;
System.out.println("生產者"+Thread.currentThread().getName()+"----"+sp);
f=false;
this.notifyAll();
/*
這裡用notifyAll()方法就是為了讓全部沉睡的執行緒醒來
既喚醒了生產者又喚醒了消費者
此時假設f=true那麼因為之前的while作用。消費者即使是得到許可權(鎖)也不能執行僅僅能凍結,所以僅僅有一個生產者能夠得到許可權執行。
此時假設是f=false那麼因為之前的while作用,生產者即使是得到許可權(鎖)也不能執行僅僅能凍結所以僅僅有一個消費者能夠得到許可權執行。
*/
}
}
public synchronized void xiaofei( )
{
while(true)
{
while(f==true)
try{this.wait();} catch(Exception e){}
System.out.println("消費者"+Thread.currentThread().getName()+"----"+sp);
f=true;
this.notifyAll();
}
}
}
class Shengchangzhe implements Runnable
{
private Shipin a ;
Shengchangzhe(Shipin a)
{
this.a=a;
}
public void run()
{
a.shengchang();
}
}
class Xiaofeizhe implements Runnable
{
private Shipin a ;
Xiaofeizhe(Shipin a)
{
this.a=a;
}
public void run()
{
a.xiaofei();
}
}
class Xctx5
{
public static void main(String[] args)
{
Shipin a=new Shipin();
Shengchangzhe b1=new Shengchangzhe(a);
Shengchangzhe b2=new Shengchangzhe(a);
Xiaofeizhe b3=new Xiaofeizhe(a);
Xiaofeizhe b4=newXiaofeizhe(a);
Thread t1=new Thread(b1);
Thread t2=new Thread(b2);
Thread t3=new Thread(b3);
Thread t4=new Thread(b4);
t1.start();
t2.start();
t3.start();
t4.start();
System.out.println("HelloWorld!");
}
}
/*
以上程式編譯執行結果例如以下:
生產者Thread-0----1
Hello World!
消費者Thread-3----1
生產者Thread-1----2
消費者Thread-2----2
生產者Thread-0----3
消費者Thread-3----3
生產者Thread-1----4
消費者Thread-2----4
生產者Thread-0----5
消費者Thread-3----5
生產者Thread-1----6
消費者Thread-2----6
生產者Thread-0----7
消費者Thread-3----7
生產者Thread-1----8
消費者Thread-2----8
生產者Thread-0----9
消費者Thread-3----9
生產者Thread-1----10
消費者Thread-2----10
生產者Thread-0----11
消費者Thread-3----11
生產者Thread-1----12
消費者Thread-2----12
生產者Thread-0----13
消費者Thread-3----13
生產者Thread-1----14
消費者Thread-2----14
生產者Thread-0----15
消費者Thread-3----15
生產者Thread-1----16
消費者Thread-2----16
生產者Thread-0----17
消費者Thread-3----17
生產者Thread-1----18
消費者Thread-2----18
生產者Thread-0----19
消費者Thread-3----19
生產者Thread-1----20
消費者Thread-2----20
生產者Thread-0----21
消費者Thread-3----21
生產者Thread-1----22
消費者Thread-2----22
生產者Thread-0----23
消費者Thread-3----23
生產者Thread-1----24
消費者Thread-2----24
生產者Thread-0----25
消費者Thread-3----25
生產者Thread-1----26
消費者Thread-2----26
生產者Thread-0----27
消費者Thread-3----27
生產者Thread-1----28
消費者Thread-2----28
生產者Thread-0----29
消費者Thread-3----29
生產者Thread-1----30
消費者Thread-2----30
生產者Thread-0----31
*/
——————切割線————
//另外一個是jdk1.5版本號升級後的情況:
import java.util.concurrent.locks.*;
//這個匯入的是後面須要用到的類
/*
隨著jdk1.5版本號的升級,一些新的功能也被增加。更加的方便使用者
就拿多執行緒通訊的生產者消費者樣例來說
*/
class Xctx6
{
public static void main(String[] args)
{
Shipin a=new Shipin();
Shengchangzhe b1=new Shengchangzhe(a);
Xiaofeizhe b2=new Xiaofeizhe(a);
Thread t1=new Thread(b1);
Thread t2=new Thread(b1);
Thread t3=new Thread(b2);
Thread t4=new Thread(b2);
t1.start();
t2.start();
t3.start();
t4.start();
System.out.println("HelloWorld!");
}
}
class Shipin
{
private int sp=0;
private boolean f=true;
private Lock lock=new ReentrantLock();//將鎖作為一個物件了
private Condition pro= lock.newCondition();
private Condition con= lock.newCondition();
/*
Condition將Object監視器(鎖)的方法(wait,notify。notifyAll)分解成不同的物件,
這是為了便於與Lock組合使用。
Lock取代synchronized方法和語句的使用(同步函式和同步程式碼塊)
Condition替代了Object監視器(鎖)的方法的使用。
Condition例項是繫結在鎖上的。一個Lock例項要獲得Condition例項就要呼叫newCondition方法。
*/ public void shengchang() throws InterruptedException { lock.lock(); try { while(f==false) pro.await();//生產者執行緒陷入凍結 //這個句式會丟擲一個InterruptedException異常 sp++; System.out.println("生產者"+Thread.currentThread().getName()+"----"+sp); f=false; con.signal();//只喚醒消費者執行緒 } finally { lock.unlock();//釋放鎖 } /* 這裡是所以要使用try...finally句型是由於確保 一定要執行 lock.unlock();也是由於前面的pro.await();會向外丟擲 一個異常,假設沒有這個句型程式就會跳出去而沒有 執行lock.unlock();這種話執行緒就沒有釋放鎖 */ } public void xiaofei() throws InterruptedException { lock.lock(); try { while(f==true) con.await();//消費者執行緒陷入凍結 System.out.println("消費者"+Thread.currentThread().getName()+"----"+sp); f=true; pro.signal();//喚醒生產者執行緒 } finally { lock.unlock(); } } } class Shengchangzhe implements Runnable { private Shipin a ; Shengchangzhe(Shipin a) { this.a=a; } public void run() { while(true) { try{a.shengchang();} catch(Exception e){} } } } class Xiaofeizhe implements Runnable { private Shipin a ; Xiaofeizhe(Shipin a) { this.a=a; } public void run() { while(true) { try{a.xiaofei();} catch(Exception e){} } } }
/*
對前面的樣例做了一個改進:
有生產者,檢查者。消費者
先要由生產者生產食品,
然後由檢查者檢測食品。
最後由消費者消化食品。
*/
import java.util.concurrent.locks.*;
class Xctx7
{
public static void main(String[] args)
{
Shipin a=new Shipin();
Shengchangzhe b1=new Shengchangzhe(a);
Xiaofeizhe b2=new Xiaofeizhe(a);
Jiancezhe b3=new Jiancezhe(a);
Thread t1=new Thread(b1);
Thread t2=new Thread(b1);
Thread t3=new Thread(b2);
Thread t4=new Thread(b2);
Thread t5=new Thread(b3);
Thread t6=new Thread(b3);
t1.start();
t2.start();
t3.start();
t4.start();
t5.start();
t6.start();
System.out.println("HelloWorld!");
}
}
class Shipin
{
private int sp=0;
private int f=1;
private Lock lock=new ReentrantLock();//將鎖作為一個物件了
private Condition pro= lock.newCondition();
private Condition con= lock.newCondition();
private Condition jc = lock.newCondition();
public void shengchang() throws InterruptedException
{
lock.lock();
try
{
while(f!=1)
{
pro.await();//生產者執行緒陷入凍結
}
sp++;
System.out.println("生產者"+Thread.currentThread().getName()+"----"+sp);
f=2;
jc.signal();//喚醒檢測者執行緒
}
finally
{
lock.unlock();//釋放鎖
}
}
public void xiaofei() throws InterruptedException
{
lock.lock();
try
{
while(f!=3)
{
con.await();//消費者執行緒陷入凍結
}
System.out.println("消費者"+Thread.currentThread().getName()+"----------"+sp);
f=1;
pro.signal();//喚醒生產者執行緒
}
finally
{
lock.unlock();
}
}
public void jiance() throws InterruptedException //檢測方法
{
lock.lock();
try
{
while(f!=2)
{
jc.await();//檢測者執行緒陷入凍結
}
System.out.println("檢測者"+Thread.currentThread().getName()+"-------"+sp);
f=3;
con.signal();//喚醒消費者執行緒
}
finally
{
lock.unlock();
}
}
}
class Shengchangzhe implements Runnable
{
privateShipin a ;
Shengchangzhe(Shipin a)
{
this.a=a;
}
public void run()
{
while(true)
{
try{a.shengchang();}
catch(Exception e){}
}
}
}
class Xiaofeizhe implements Runnable
{
private Shipin a ;
Xiaofeizhe(Shipin a)
{
this.a=a;
}
public void run()
{
while(true)
{
try{a.xiaofei();}
catch(Exception e){}
}
}
}
class Jiancezhe implements Runnable
{
private Shipin a ;
Jiancezhe(Shipin a)
{
this.a=a;
}
public void run()
{
while(true)
{
try{a.jiance();}
catch(Exception e){}
}
}
}
/*
以上的程式碼編譯執行結果例如以下:
生產者Thread-0----1
Hello World!
檢測者Thread-4-------1
消費者Thread-3----------1
生產者Thread-0----2
檢測者Thread-5-------2
消費者Thread-3----------2
生產者Thread-1----3
檢測者Thread-5-------3
消費者Thread-2----------3
生產者Thread-0----4
檢測者Thread-4-------4
消費者Thread-3----------4
生產者Thread-1----5
檢測者Thread-5-------5
消費者Thread-2----------5
生產者Thread-0----6
檢測者Thread-4-------6
消費者Thread-3----------6
生產者Thread-1----7
檢測者Thread-5-------7
消費者Thread-2----------7
生產者Thread-0----8
檢測者Thread-4-------8
消費者Thread-3----------8
生產者Thread-1----9
檢測者Thread-5-------9
消費者Thread-2----------9
生產者Thread-0----10
檢測者Thread-4-------10
消費者Thread-3----------10
生產者Thread-1----11
檢測者Thread-5-------11
消費者Thread-2----------11
生產者Thread-0----12
檢測者Thread-4-------12
消費者Thread-3----------12
生產者Thread-1----13
檢測者Thread-5-------13
消費者Thread-2----------13
生產者Thread-0----14
檢測者Thread-4-------14
消費者Thread-3----------14
生產者Thread-1----15
檢測者Thread-5-------15
消費者Thread-2----------15
生產者Thread-0----16
檢測者Thread-4-------16
消費者Thread-3----------16
生產者Thread-1----17
檢測者Thread-5-------17
消費者Thread-2----------17
生產者Thread-0----18
檢測者Thread-4-------18
消費者Thread-3----------18
生產者Thread-1----19
檢測者Thread-5-------19
消費者Thread-2----------19
生產者Thread-0----20
檢測者Thread-4-------20
消費者Thread-3----------20
生產者Thread-1----21
檢測者Thread-5-------21
消費者Thread-2----------21
生產者Thread-0----22
檢測者Thread-4-------22
消費者Thread-3----------22
生產者Thread-1----23
檢測者Thread-5-------23
消費者Thread-2----------23
生產者Thread-0----24
檢測者Thread-4-------24
消費者Thread-3----------24
生產者Thread-1----25
檢測者Thread-5-------25
消費者Thread-2----------25
生產者Thread-0----26
檢測者Thread-4-------26
消費者Thread-3----------26
生產者Thread-1----27
檢測者Thread-5-------27
消費者Thread-2----------27
生產者Thread-0----28
檢測者Thread-4-------28
消費者Thread-3----------28
生產者Thread-1----29
檢測者Thread-5-------29
消費者Thread-2----------29
生產者Thread-0----30
檢測者Thread-4-------30
消費者Thread-3----------30
生產者Thread-1----31
檢測者Thread-5-------31
消費者Thread-2----------31
生產者Thread-0----32
檢測者Thread-4-------32
消費者Thread-3----------32
生產者Thread-1----33
檢測者Thread-5-------33
消費者Thread-2----------33
生產者Thread-0----34
檢測者Thread-4-------34
消費者Thread-3----------34
生產者Thread-1----35
檢測者Thread-5-------35
消費者Thread-2----------35
生產者Thread-0----36
檢測者Thread-4-------36
消費者Thread-3----------36
生產者Thread-1----37
檢測者Thread-5-------37
消費者Thread-2----------37
生產者Thread-0----38
檢測者Thread-4-------38
消費者Thread-3----------38
生產者Thread-1----39
檢測者Thread-5-------39
消費者Thread-2----------39
生產者Thread-0----40
檢測者Thread-4-------40
消費者Thread-3----------40
生產者Thread-1----41
檢測者Thread-5-------41
消費者Thread-2----------41
生產者Thread-0----42
檢測者Thread-4-------42
消費者Thread-3----------42
生產者Thread-1----43
檢測者Thread-5-------43
消費者Thread-2----------43
生產者Thread-0----44
檢測者Thread-4-------44
消費者Thread-3----------44
生產者Thread-1----45
檢測者Thread-5-------45
消費者Thread-2----------45
生產者Thread-0----46
檢測者Thread-4-------46
消費者Thread-3----------46
生產者Thread-1----47
檢測者Thread-5-------47
消費者Thread-2----------47
生產者Thread-0----48
檢測者Thread-4-------48
消費者Thread-3----------48
生產者Thread-1----49
檢測者Thread-5-------49
消費者Thread-2----------49
生產者Thread-0----50
檢測者Thread-4-------50
消費者Thread-3----------50
生產者Thread-1----51
檢測者Thread-5-------51
消費者Thread-2----------51
生產者Thread-0----52
檢測者Thread-4-------52
消費者Thread-3----------52
生產者Thread-1----53
檢測者Thread-5-------53
消費者Thread-2----------53
生產者Thread-0----54
檢測者Thread-4-------54
消費者Thread-3----------54
生產者Thread-1----55
檢測者Thread-5-------55
消費者Thread-2----------55
生產者Thread-0----56
檢測者Thread-4-------56
消費者Thread-3----------56
生產者Thread-1----57
檢測者Thread-5-------57
消費者Thread-2----------57
生產者Thread-0----58
檢測者Thread-4-------58
消費者Thread-3----------58
生產者Thread-1----59
檢測者Thread-5-------59
消費者Thread-2----------59
生產者Thread-0----60
檢測者Thread-4-------60
消費者Thread-3----------60
生產者Thread-1----61
檢測者Thread-5-------61
消費者Thread-2----------61
生產者Thread-0----62
檢測者Thread-4-------62
消費者Thread-3----------62
生產者Thread-1----63
檢測者Thread-5-------63
消費者Thread-2----------63
*/