日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

Java学习个人备忘录之线程间的通信

發布時間:2025/7/14 java 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java学习个人备忘录之线程间的通信 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
線程間通訊
多個線程在處理同一資源,但是任務卻不同.?

class Resource { String name; String sex; } //輸入 class Input implements Runnable { Resource r; Input(Resource r) { this.r = r; } public void run() { int i = 0; while(true) { synchronized(r) //保證兩個線程用同一個鎖 { if (i==0) { r.name = "mike"; r.sex = "nan"; } else { r.name = "麗麗"; r.name = "女女女女女女女女女"; } x = (x+1)%2; } } } } //輸出 class Output implements Runnable { Resource r; Output(Resource r) { this.r = r; } public void run() { while(true) { synchronized(r) //保證兩個線程用同一個鎖 { System.out.println(r.name+"....."+r.sex); } } } } class ResourceDemo { public static void main(String[] args) { //創建資源 Resource r = new Resource(); //創建任務 Input in = new Input(r); Output out = new Output(r); //創建線程 Thread t1 = new Thread(in); Thread t2 = new Thread(out); //開啟線程 t1.start(); t2.start(); } }

但是這樣會造成大量的才重復, 沒有交替性。

?

等待喚醒機制

涉及的方法:
1. wait(): 讓線程處于凍結狀態, 被wait的線程會被存儲到線程池中.
2. notify(): 喚醒線程池中一個線程(任意)
3. notifyAll(): 喚醒線程池中的所有線程.


這些方法都必須定義在同步中,
因為這些方法都是用于操做線程狀態的方法.
必須要明確到底操做的是哪個鎖上的線程.


為什么操做線程的方法wait notify notifyAll定義在了Object類中.

因為這些方法時監視器的方法, 堅持其其實就是鎖.
鎖可以是任意的對象,任意的對象調用的方式一定定義在Object類中的.?

class Resource { String name; String sex; boolean flag = false; } //輸入 class Input implements Runnable { Resource r; Input(Resource r) { this.r = r; } public void run() { int i = 0; while(true) { synchronized(r) //保證兩個線程用同一個鎖 { if (r.flag) { r.wait(); } if (i==0) { r.name = "mike"; r.sex = "nan"; } else { r.name = "麗麗"; r.name = "女女女女女女女女女"; } r.flag = true; r.notify(); //喚醒對方 x = (x+1)%2; } } } } //輸出 class Output implements Runnable { Resource r; Output(Resource r) { this.r = r; } public void run() { while(true) { synchronized(r) //保證兩個線程用同一個鎖 { if (!r.flag) { r.wait(); } System.out.println(r.name+"....."+r.sex); r.flag = false; r.notify(); //喚醒對方 } } } } class ResourceDemo2 { public static void main(String[] args) { //創建資源 Resource r = new Resource(); //創建任務 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 Resource { private String name; //這里要私有化 private String sex; boolean flag = false; public synchronized void set(String name,String sex) //對數據要可控化 { if (this.flag) try{this.wait();}catch(InterruptedException e){} this.name = name; this.sex = sex; flag = true; this.notify(); } public synchronized void out() { if (this.flag) try{this.wait();}catch(InterruptedException e){} System.out.println(name+"....."+sex); flag = false; this.notify(); } } //輸入 class Input implements Runnable { Resource r; Input(Resource r) { this.r = r; } public void run() { int i = 0; while(true) { if (i==0) { r.set("mike","nan"); } else { r.set"麗麗","女女女女女女女女女"); } x = (x+1)%2; } } } //輸出 class Output implements Runnable { Resource r; Output(Resource r) { this.r = r; } public void run() { while(true) { r.out(); } } } class ResourceDemo3 { public static void main(String[] args) { //創建資源 Resource r = new Resource(); //創建任務 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 Resource { private String name; private int count = 1; private boolean flag = false; public synchronized void set(String name) { if (flag) try{this.wait();}catch(InterruptedException e){} this.name = name + count; count++; System.out.println(Thread.currentThread().getName()+".....生產者....."+this.name); flag = true; notify(); } public synchronized void out() { if (!flag) try{this.wait();}catch(InterruptedException e){} System.out.println(Thread.currentThread().getName()+".....消費者....."+this.name); 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 t0 = new Thread(pro); Thread t1 = new Thread(pro); Thread t2 = new Thread(con); Thread t3 = new Thread(con); t0.start(); t1.start(); t2.start(); t3.start(); } }

但是這樣會出現安全隱患, 從這4個線程上看, 一共分了兩組, t0和t1一組, t2和t3一組, 當t1 t2 t3 睡眠時, t0出來后再次喚醒t1, 這時t1是不用判斷的if條件的,直接向下繼續執行. 這樣就又進行了"生產烤鴨", 所以出現了安全隱患. 解決辦法: 將兩個if 換成 while, 這樣在t1醒來的時候會繼續判斷flag是否為真. 但是這樣又會出現死鎖現象, 因為t1判斷flag時, flag為真, 這時t1會再次等待,這時4個線程都進入等待狀態---死鎖!!

?

解決辦法1
將notify換成notifyAll, 這樣就一定會喚醒對方的線程,同時自己方的線程因為while循環出不去.?

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){} this.name = name + count; count++; System.out.println(Thread.currentThread().getName()+".....生產者....."+this.name); flag = true; notifyAll(); } public synchronized void out() { while (!flag) try{this.wait();}catch(InterruptedException e){} System.out.println(Thread.currentThread().getName()+".....消費者....."+this.name); flag = false; notifyAll(); } } 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 t0 = new Thread(pro); Thread t1 = new Thread(pro); Thread t2 = new Thread(con); Thread t3 = new Thread(con); t0.start(); t1.start(); t2.start(); t3.start(); } }

if判斷標記只有一次, 會導致不該運行的線程運行了, 出現了數據錯誤的情況.?while判斷標記, 解決了線程獲取執行權后, 是否要運行。
notify: 只能喚醒一個線程, 如果本方喚醒了本方, 就沒有意義, 而且while判斷標記notify會導致死鎖.?notifyAll解決了, 本方線程一定會喚醒對方線程.?

解決辦法2:
JDK1.5新特征的解決辦法--Lock

可以看出來, 上面的解決方法會造成多次無用的判斷, 這會降低效率,可以用這面的方法解決.?

Lock l = new ReentrantLock(); void show() { l.lock(); //獲取鎖 code... l.unlock(); //釋放鎖 }

jdk1.5以后將同步和鎖封裝成了對象.
并將操作鎖的隱式方法定義到了該對象中,
將隱式動作變成了顯示動作.

但是如果執行的代碼拋出了異常, 這樣代碼就會一直持有鎖,不釋放,所以要如下

Lock l = new ReentrantLock(); void show() { l.lock(); //獲取鎖 try { code... } finally { l.unlock(); //釋放鎖 } }

?

import java.util.concurrent.locks.* class Resource { private String name; private int count = 1; private boolean flag = false; Lock l = new ReentrantLock();//因為Lock是java.util.concurrent.locks包中的類, 所以要先導入包. public void set(String name) //這里的同步就可以去掉了 { l.lock(); //在這里加上鎖 try { while (flag) try{this.wait();}catch(InterruptedException e){} this.name = name + count; count++; System.out.println(Thread.currentThread().getName()+".....生產者....."+this.name); flag = true; notifyAll(); } finally { l.unlock(); } } public void out() { l.lock(); try { while (!flag) try{this.wait();}catch(InterruptedException e){} System.out.println(Thread.currentThread().getName()+".....消費者....."+this.name); flag = false; notifyAll(); } finally { l.unlock(); } } } 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 t0 = new Thread(pro); Thread t1 = new Thread(pro); Thread t2 = new Thread(con); Thread t3 = new Thread(con); t0.start(); t1.start(); t2.start(); t3.start(); } }

解決辦法3:
JDK1.5新特征的解決辦法--Condition

Condition在底層上是這樣實現的:
interface Condition
{
  await();
  signal();
  signalAll();
}

所以要這樣實現, 如下:
Lock l = new ReectrantLock();

Condition c1 = l.newCondition();

Condition c2 = l.newCondition();

import java.util.concurrent.locks.* class Resource { private String name; private int count = 1; private boolean flag = false; //創建一個鎖對象. Lock l = new ReentrantLock();//因為Lock是java.util.concurrent.locks包中的類, 所以要先導入包. //通過已有的鎖獲取該鎖上的監視器對象. Condition con = l.newCondition(); public void set(String name) //這里的同步就可以去掉了 { l.lock(); //在這里加上鎖 try { while (flag) // try{this.wait();}catch(InterruptedException e){} //這里用con.await()替換 try{con.await();}catch(InterruptedException e){} this.name = name + count; count++; System.out.println(Thread.currentThread().getName()+".....生產者....."+this.name); flag = true; // notifyAll(); //這里用con.signalAll() 替換 con.signalAll(); } finally { l.unlock(); } } public void out() { l.lock(); try { while (!flag) // try{this.wait();}catch(InterruptedException e){} //這里用con.await()替換 try{con.await();}catch(InterruptedException e){} System.out.println(Thread.currentThread().getName()+".....消費者....."+this.name); flag = false; // notifyAll(); //這里用con.signalAll() 替換 con.signalAll(); } finally { l.unlock(); } } } 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 ProducerConsumerDemo2 { public static void main(String[] args) { Resource r = new Resource(); Producer pro = new Producer(r); Consumer con = new Consumer(r); Thread t0 = new Thread(pro); Thread t1 = new Thread(pro); Thread t2 = new Thread(con); Thread t3 = new Thread(con); t0.start(); t1.start(); t2.start(); t3.start(); } }

其實解決辦法3和解決辦法2沒有太大的區別.并沒有真的運用了1.5的新特征。

解決辦法4
這個解決辦法才真正的運用到了1.5的新特征。

import java.util.concurrent.locks.* class Resource { private String name; private int count = 1; private boolean flag = false; //創建一個鎖對象. Lock l = new ReentrantLock();//因為Lock是java.util.concurrent.locks包中的類, 所以要先導入包. //通過已有的鎖獲取該鎖上的監視器對象. // Condition con = l.newCondition(); //通過已有的鎖獲取兩組監視器, 一組監視生產者, 一組監視消費者. Condition producer_con = l.newCondition(); Condition consumer_con = l.newCondition(); public void set(String name) //這里的同步就可以去掉了 { l.lock(); //在這里加上鎖 try { while (flag) try{producer_con.await();}catch(InterruptedException e){} //這里只讓生產者等待 this.name = name + count; count++; System.out.println(Thread.currentThread().getName()+".....生產者....."+this.name); flag = true; consumer_con.signal(); //這里直接喚醒消費者 } finally { l.unlock(); } } public void out() { l.lock(); try { while (!flag) try{consumer_con.await();}catch(InterruptedException e){} //這里只讓消費者等待 System.out.println(Thread.currentThread().getName()+".....消費者....."+this.name); flag = false; producer_con.signalAll(); //這里只喚醒生產者 } finally { l.unlock(); } } } 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 ProducerConsumerDemo2 { public static void main(String[] args) { Resource r = new Resource(); Producer pro = new Producer(r); Consumer con = new Consumer(r); Thread t0 = new Thread(pro); Thread t1 = new Thread(pro); Thread t2 = new Thread(con); Thread t3 = new Thread(con); t0.start(); t1.start(); t2.start(); t3.start(); } }

?

轉載于:https://www.cnblogs.com/y-zr/p/7906007.html

總結

以上是生活随笔為你收集整理的Java学习个人备忘录之线程间的通信的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。