標籤:
線程間通訊,其實就是多個線程在操作同一個資源,但操作動作不同。 同步代碼塊用了同一個鎖。 public class Test{ public static void main(String args []) { Res r = new Res(); Input in = new Input(r); Output out = new Output(r); Thread t1 = new Thread(in); Thread t2 =new Thread(out); t1.start(); t2.start(); }} class Res{ String name; String sex;} class Input implements Runnable{ Res r ; Input(Res r) { this.r = r; } public void run() { boolean b = true; while(true) { synchronized(r) { if(b) { r.name="mike"; r.sex="man"; b=false; } else { r.name="麗麗"; r.sex="女女女女"; b=true; } } } }} class Output implements Runnable{ Res r; Output(Res r) { this.r=r; } public void run() { while(true) { synchronized(r) { System.out.println(r.name+"....."+r.sex); } } }} 改代碼 會列印重複的 同一個人,利用線程直接的通訊修改,在Res中給一個標記。
等待喚醒機制
非靜態同步函數用的鎖時this。靜態同步函數用的鎖時 類名.class。同步代碼塊用的鎖任意。自己設定的 wait() :格式 try{} catch() {}notify() notifyAll() 三個方法都繼承於Object類,後兩個方法必須有對象的監視器才可以使用(也就是同步中的鎖,必須在同步中才可以使用) 都使用在同步中,因為要對持有監視器(鎖)的線程操作,所以要使用在同步中,因為只有在同步中,才有鎖。 為什麼操作線程的方法要定義在Object中呢,因為這些方法在操作同步中的線程時,都必須要標示他們所操作線程持有的鎖,只有同一個鎖上的被等待線程可以被同一個鎖上notify()喚醒,不可以對不同所中的線程進行喚醒也就是說,等待和喚醒必須是同一個鎖,而鎖可以是任意對象,所以可以被任意對象調用的方法定義在Obj類中。 public class Test{ public static void main(String args []) { Res r = new Res(); Input in = new Input(r); Output out = new Output(r); Thread t1 = new Thread(in); Thread t2 =new Thread(out); t1.start(); t2.start(); }} class Res{ String name; String sex; boolean flag = false;} class Input implements Runnable{ Res r ; Input(Res r) { this.r = r; } public void run() { boolean b = true; while(true) { synchronized(r) { if(r.flag) try { r.wait(); } catch(Exception e) { } if(b) { r.name="mike"; r.sex="man"; b=false; } else { r.name="麗麗"; r.sex="女女女女"; b=true; } r.flag=true; r.notify(); } } }} class Output implements Runnable{ Res r; Output(Res r) { this.r=r; } public void run() { while(true) { synchronized(r) { if(!r.flag) try { r.wait(); } catch(Exception e) { } System.out.println(r.name+"....."+r.sex); r.flag=false; r.notify(); } } }} 繼續舉例:多個線程負責生產,多個線程負責消費。注意notifyAll 和while(flag) 對於多個生產者和消費者。為什麼要定義while判斷標記?讓被喚醒的線程再一次判斷標記。 為什麼要定義notifyAll因為需要喚醒對方線程。因為只用notify的話,容易出只喚醒本方線程的情況,導致程式中所有線程都等待。 public class Test{ 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); Thread t3 = new Thread(pro); Thread t4 = new Thread(con); t1.start(); t2.start(); t3.start(); t4.start(); }} class Resource{ private String name; private int count = 1; private boolean flag = false; public synchronized void set(String name) { while(flag) try { wait(); } catch(Exception e) { } this.name = name+"--"+count++; System.out.println(Thread.currentThread().getName()+"...生產者.."+this.name); flag = true; this.notifyAll(); } public synchronized void out() { while(!flag) try { wait(); } catch(Exception e) { } System.out.println(Thread.currentThread().getName()+"...消費者......."+this.name); flag = false; this.notifyAll(); } } class Producer implements Runnable{ private Resource res; public void run() { while(true) { res.set("+商品+"); } } Producer(Resource res) { this.res=res; }} class Consumer implements Runnable{ private Resource res; public void run() { while(true) { res.out(); } } Consumer(Resource res) { this.res=res; } }
jdk5升級之後
java.util.concurrent.locks 介面 jdk1.5中提供了多線程的升級解決方案,將同步的Synchronized 替換成Lock操作,將Object中的wait,notify,nofityAll替換成立Condition對象,該對象可以Lock鎖,進行擷取。一個鎖可以對應多個Condition。 JDK1.5 中提供了多線程升級解決方案。將同步Synchronized替換成現實Lock操作。將Object中的wait,notify notifyAll,替換了Condition對象。該對象可以Lock鎖 進行擷取。該樣本中,實現了本方只喚醒對方操作。 Lock:替代了Synchronized lock unlock new Condition() Condition:替代了Object wait notify notifyAll await(); signal(); signalAll(); 在該實力中,實現了本方只喚醒對方的操作。更改之後的代碼: import java.util.concurrent.locks.*; class Test{ 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(pro); Thread t3 = new Thread(con); Thread t4 = new Thread(con); t1.start(); t2.start(); t3.start(); t4.start(); }} /*JDK1.5 中提供了多線程升級解決方案。將同步Synchronized替換成現實Lock操作。將Object中的wait,notify notifyAll,替換了Condition對象。該對象可以Lock鎖 進行擷取。該樣本中,實現了本方只喚醒對方操作。 Lock:替代了Synchronized lock unlock newCondition() Condition:替代了Object wait notify notifyAll await(); signal(); signalAll();*/class Resource{ private String name; private int count = 1; private boolean flag = false; // t1 t2 private Lock lock = new ReentrantLock(); private Condition condition_pro = lock.newCondition(); private Condition condition_con = lock.newCondition(); public void set(String name)throws InterruptedException { lock.lock(); try { while(flag) condition_pro.await();//t1,t2 this.name = name+"--"+count++; System.out.println(Thread.currentThread().getName()+"...生產者.."+this.name); flag = true; condition_con.signal(); } finally { lock.unlock();//釋放鎖的動作一定要執行。 } } // t3 t4 public void out()throws InterruptedException { lock.lock(); try { while(!flag) condition_con.await(); System.out.println(Thread.currentThread().getName()+"...消費者........."+this.name); flag = false; condition_pro.signal(); } finally { lock.unlock(); } }} class Producer implements Runnable{ private Resource res; Producer(Resource res) { this.res = res; } public void run() { while(true) { try { res.set("+商品+"); } catch (InterruptedException e) { } } }} class Consumer implements Runnable{ private Resource res; Consumer(Resource res) { this.res = res; } public void run() { while(true) { try { res.out(); } catch (InterruptedException e) { } } }}
停止線程
停止線程的原理只有一種方法,就是run()方法結束 線程.interrupt //強制喚醒 stop方法已經過時。 如何停止線程?只有一種,run方法結束。開啟多線程運行,運行代碼通常是迴圈結構。 只要控制住迴圈,就可以讓run方法結束,也就是線程結束。 特殊情況:當線程處於了凍結狀態。就不會讀取到標記。那麼線程就不會結束。 當沒有指定的方式讓凍結的線程恢複到運行狀態是,這時需要對凍結進行清除。強制讓線程恢複到運行狀態中來。這樣就可以操作標記讓線程結束。 Thread類提供該方法 interrupt(); 設定為守護線程,當其他線程都結束後,並且只剩下守護線程,守護線程自動結束而且必須早start()之前設定守護線程
join方法 t1.join(); 搶奪cpu執行權,當t1執行結束的時候,主線程才解凍。 join:當A線程執行到了B線程的.join()方法時,A就會等待。等B線程都執行完,A才會執行。 join可以用來臨時加入線程執行。
線程的優先順序
自己寫的代碼:import java.util.concurrent.locks.*;import java.util.concurrent.locks.Lock.*; public class Test{ public static void main(String args[]) { Resource r = new Resource(); Pro p = new Pro(r); Cro c = new Cro(r); Thread t1 = new Thread(p); Thread t2 = new Thread(p); Thread t3 = new Thread(c); Thread t4 = new Thread(c); t1.start(); t2.start(); t3.start(); t4.start(); }} class Resource{ private boolean flag = false; private int count = 1; private Lock lock = new ReentrantLock(); private Condition con_pro = lock.newCondition(); private Condition con_con = lock.newCondition(); public void set() { lock.lock(); try { while(flag) con_pro.await(); count++; System.out.println(Thread.currentThread().getName()+"生產了第"+count+"張票"); flag=true; con_con.signal(); } catch (InterruptedException e) { } finally { lock.unlock(); } } public void hua() { lock.lock(); try { while(!flag) con_con.await(); System.out.println(Thread.currentThread().getName()+"消費了第"+count+"張票***"); flag=false; con_pro.signal(); } catch (InterruptedException e) { } finally { lock.unlock(); } } } class Pro implements Runnable{ Resource r; Pro(Resource r) { this.r=r; } public void run() { while(true) r.set(); }} class Cro implements Runnable{ Resource r; Cro(Resource r) { this.r=r; } public void run() { while(true) r.hua(); }}
JAVA 11(多線程)