Java第十四天學習筆記~多執行緒(執行緒直接通訊---等待喚醒機制、多生產者多消費者問題、JDK1.5新特性、wait和sleep區別)
執行緒直接通訊示例
//資源 class Resource { String name; String sex; } //輸入 class Input implements Runnable { Resource r; Input(Resource r) { this.r=r; } public void run() { int x=0; while(true) { if(x==0) { r.name="mike"; r.sex="nan"; } else { r.name="麗麗"; r.sex="女女女女女女女女女女"; } x=x++%2; } } } //輸出 class Output implements Runnable { Resource r; Output(Resource r) { this.r=r; } public void run() { while(true) { System.out.println(r.name+"...."+r.sex); } } } class ResourceDemo { public static void main(String[] args) { //建立資源 Resource r=new Resource(); //建立任務 Producer in=new Producer(r); Consumer out=new Consumer(r); //建立執行緒 Thread t1=new Thread(in); Thread t2=new Thread(out); //開啟執行緒 t1.start(); t2.start(); } }
等待喚醒機制
涉及的方法:
- wait( ):讓執行緒處於凍結狀態,被wait的執行緒會被儲存到執行緒池中
- notify():喚醒執行緒池中一個執行緒(任意)
- notifyAll():喚醒執行緒池中的所有執行緒
這些方法是用於操作執行緒狀態的方法
必須要明確到底操作的是哪個鎖上的執行緒
為什麼操作執行緒的方法 wait notify notifyAll 定義在了Object類中
因為這些方法是監視器方法,監視器其實就是鎖,鎖可以是任意物件,任意物件呼叫的方式一定定義在Object類中
多生產者多消費者問題
/*多生產者多消費者*/ class Resource { private String name; private int count=1; private boolean flag = false; public synchronized void set (String name) { while(flag) try{this.wait();}catch(InterruptedException e){};//t1 t0 this.name=name+count;//烤鴨1 烤鴨2 烤鴨3 count++;//2 3 4 System.out.println(Thread.currentThread().getName()+"...生產者..."+this.name);//生產烤鴨1 生產烤鴨2 生產烤鴨3 flag=true; notify(); } public synchronized void out()//t3 { while(!flag) try{this.wait();}catch(InterruptedException e){};//t2 t3 System.out.println(Thread.currentThread().getName()+"...消費者..."+this.name);//消費烤鴨1 flag=false; notify(); } } class Producer implements Runnable { private Resource r; Producer(Resource r) { this.r=r; } public void run() { while(true) { r.set("烤鴨"); } } } class Consumer implements Runnable { private Resource r; Consumer(Resource r) { this.r=r; } public void run() { while(true) { r.out(); } } } class ProducerConsumerDemo { public static void main(String[] args) { Resource r=new Resource(); Producer pro=new Producer(r); Consumer con=new Consumer(r); Thread t1=new Thread(pro); Thread t2=new Thread(con); t1.start(); t2.start(); } }
while標記,解決了執行緒換區執行權後是否要執行
notifyAll解決了,本方執行緒一定會喚醒對方執行緒
notify:只能喚醒一個執行緒,喚醒本方執行緒無意義而且while判斷標記+notify會導致死鎖
if判斷標記:只有一次,會導致不該執行的執行緒執行,出現數據錯誤情況
JDK1.5新特性
將同步和鎖封裝成了物件,並將操作鎖的隱式方式定義到了該物件中,將隱式動作變成了顯示動作
建立一個鎖物件
lock lock=new Reentrantlook();
void show()
{
synchronized(obj)
{
code.....; //同步程式碼塊對於鎖的操作是隱式的
}
}
void show()
{
lock.lock(); //獲取鎖
code.....;
lock.unlock(); //釋放鎖
}
通過已有的鎖獲取該鎖上的監視器物件
Condition con=lock.newCondition( );
通過已有的鎖獲取2組監視器,一組監視生產者一組監視消費者
Condition producer_con=lock.newCondition();
Condition consumer_con=lock.newCondition();
Lock介面:出現替代了同步程式碼塊或同步函式的隱式鎖,操作變成了顯示操作,同時更為靈活,可以一個鎖上加上多組監視器
lock():獲取鎖
unlock():釋放鎖,通常需定義finally程式碼塊中
Condition介面:出現代替了object中的wait notify notifyAll 方法,將這些監視器方法單獨進行封裝,變成condition監視器物件,可以任意鎖進行組合。
await();
signal();
signalAll();
wait和sleep區別?
//sleep和wait區別
class Demo
{
void show()
{
synchronized(this)
{
wait();//t0 t1 t2
}
}
void method()
{
synchronized(this)
{
//wait();
notifyAll();
}//t4
}
}
class
{
public static void main(String[] args)
}
1、wait可以指定時間也可以不指定
sleep必須指定時間
2、在同步時,對CPU的執行權和鎖的處理不同
wait:釋放執行權,釋放鎖
sleep:釋放執行權,不釋放鎖
執行緒的停止
run方法結束:開啟多執行緒執行,執行程式碼通常是迴圈結構。只要控制住迴圈,就可以讓run方法結束,也就是執行緒結束。
特殊情況:當執行緒處於了凍結狀態。就不會讀取到標記。那麼執行緒就不會結束。
當沒有指定的方式讓凍結的執行緒恢復到執行狀態是,這時需要對凍結進行清除。
強制讓執行緒恢復到執行狀態中來。這樣就可以操作標記讓執行緒結束。Thread類提供該方法 interrupt( );
Thread的其他方法
join():當A執行緒執行到了B執行緒的.join()方法時,A就會等待。等B執行緒都執行完,A才會執行。join可以用來臨時加入執行緒執行。
setDaemon():將該執行緒標記為守護執行緒或使用者執行緒。當正在執行的執行緒都是守護執行緒時,Java 虛擬機器退出。該方法必須在啟動執行緒前呼叫。
setPriority(int newPriority):設定執行緒優先順序,級數為1~10
yield() :暫停當前正在執行的執行緒物件,並執行其他執行緒。