Java基礎(三十九)-執行緒相關
阿新 • • 發佈:2018-12-20
生產者與消費者
1:多執行緒開發之中最為著名的案例就是生產者與消費者,該操作的主要流程如下
2:實現程式基本功能和結構
public class Test { public static void main(String[] args) throws Exception { Message msg = new Message() ; new Thread(new Producer(msg)).start(); // 啟動生產者執行緒 new Thread(new Consumer(msg)).start(); // 啟動消費者執行緒 } } class Producer implements Runnable { private Message msg ; public Producer(Message msg) { this.msg = msg ; } @Override public void run() { for (int x = 0 ; x < 100 ; x ++) { if (x % 2 == 0) { this.msg.setTitle("王健"); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } this.msg.setContent("宇宙大帥哥"); } else { this.msg.setTitle("小高"); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } this.msg.setContent("猥瑣第一人,常態保持。"); } } } } class Consumer implements Runnable { private Message msg ; public Consumer(Message msg) { this.msg = msg ; } @Override public void run() { for (int x = 0 ; x < 100 ; x ++) { try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(this.msg.getTitle() + " - " + this.msg.getContent()); } } } class Message { private String title ; private String content ; public void setContent(String content) { this.content = content; } public void setTitle(String title) { this.title = title; } public String getContent() { return content; } public String getTitle() { return title; } }
執行程式碼後發現:
3:解決資料同步
class Message { private String title ; private String content ; public synchronized void set(String title,String content) { this.title = title ; try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } this.content = content ; } public synchronized String get() { try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } return this.title + " - " + this.content ; } } public class ThreadDemo { public static void main(String[] args) throws Exception { Message msg = new Message() ; new Thread(new Producer(msg)).start(); // 啟動生產者執行緒 new Thread(new Consumer(msg)).start(); // 啟動消費者執行緒 } } class Producer implements Runnable { private Message msg ; public Producer(Message msg) { this.msg = msg ; } @Override public void run() { for (int x = 0 ; x < 100 ; x ++) { if (x % 2 == 0) { this.msg.set("王健","宇宙大帥哥"); } else { this.msg.set("小高","猥瑣第一人,常態保持。"); } } } } class Consumer implements Runnable { private Message msg ; public Consumer(Message msg) { this.msg = msg ; } @Override public void run() { for (int x = 0 ; x < 100 ; x ++) { System.out.println(this.msg.get()); } } }
在進行同步處理的時候肯定需要有一個同步的處理物件,那麼此時肯定要將同步操作交由Message類處理,這個時候發現數據已經可以正常的保持一致了,但是對於重複操作任然存在。
4:執行緒等待與喚醒
如果此時有若干個執行緒的話,notify()表示的是喚醒第一個等待的,而其他執行緒繼續等待,而notify()表示會喚醒多有的執行緒,哪個執行緒的優先順序高就有可能先執行。
對於當前的問題只要的解決應該是通過Message類完成處理。
class Message { private String title ; private String content ; private boolean flag = true ; // 表示生產或消費的形式 // flag = true:允許生產,但是不允許消費 // flag = false:允許消費,不允許生產 public synchronized void set(String title,String content) { if (this.flag == false) { // 無法進行生產,應該等待被消費 try { super.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } this.title = title ; try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } this.content = content ; this.flag = false ; // 已經生產過了 super.notify(); // 喚醒等待的執行緒 } public synchronized String get() { if (this.flag == true) { // 還未生產,需要等待 try { super.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } try { return this.title + " - " + this.content ; } finally { // 不管如何都要執行 this.flag = true ; // 繼續生產 super.notify(); // 喚醒等待執行緒 } } } public class Test { public static void main(String[] args) throws Exception { Message msg = new Message() ; new Thread(new Producer(msg)).start(); // 啟動生產者執行緒 new Thread(new Consumer(msg)).start(); // 啟動消費者執行緒 } } class Producer implements Runnable { private Message msg ; public Producer(Message msg) { this.msg = msg ; } @Override public void run() { for (int x = 0 ; x < 100 ; x ++) { if (x % 2 == 0) { this.msg.set("王健","宇宙大帥哥"); } else { this.msg.set("小高","猥瑣第一人,常態保持。"); } } } } class Consumer implements Runnable { private Message msg ; public Consumer(Message msg) { this.msg = msg ; } @Override public void run() { for (int x = 0 ; x < 100 ; x ++) { System.out.println(this.msg.get()); } } }