執行緒間通訊,生產者消費者問題!
阿新 • • 發佈:2018-12-25
2、忙等待
1.執行緒間通訊的共享物件(Product)
Product類是生產者與消費者的共享類,是實現他們之間資料的共享物件。生產者生產Product,消費者消費Product,所以在Product類中,分別有一個make和一個sale方法。注意,在這兩個方法中,都使用了synchronized關鍵字,實現執行緒安全機制。在每個方法中,還用到了wait和notify方法, Obj.wait(),與Obj.notify()必須要與synchronized(Obj)一起使用,也就是wait,與notify是針對已經獲取了Obj鎖進行操作,從語法角度來說就是Obj.wait(),Obj.notify必須在synchronized(Obj){...}語句塊內。從功能上來說wait就是說執行緒在獲取物件鎖後,主動釋放物件鎖,同時本執行緒休眠。直到有其它執行緒呼叫物件的notify()喚醒該執行緒,才能繼續獲取物件鎖,並繼續執行。相應的notify()就是對物件鎖的喚醒操作。但有一點需要注意的是notify()呼叫後,並不是馬上就釋放物件鎖的,而是在相應的synchronized(){}語句塊執行結束,自動釋放鎖後,JVM會在wait()物件鎖的執行緒中隨機選取一執行緒,賦予其物件鎖,喚醒執行緒,繼續執行。
具體程式碼如下:
<span style="font-size:18px;">import java.util.ArrayList; import java.util.List; public class Product { private String name; private int count; public static List<Product> list = new ArrayList<Product>(); public String getName() { return name; } public void setName(String name) { this.name = name; } public int getCount() { return list.size(); } public void setCount(int count) { this.count = count; } public static List<Product> getList() { return list; } public static void setList(List<Product> list) { Product.list = list; } // /生產方法 public synchronized void make(Product p) { if (getCount() > 9) { try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } else { this.notifyAll(); list.add(p); } } // /消費 public synchronized void sale() { if (getCount() < 1) { try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } else { this.notifyAll(); list.remove(0); } } } </span>
2.生產者類,生產者類實現了Runnable介面,所以是一個執行緒類。原始碼如下:
<span style="font-size:18px;">public class Maker implements Runnable { Product product = new Product(); public Maker(Product product) { this.product = product; } public void run() { while (true) { try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } Product p = new Product(); p.setName("aaa"); product.make(p); System.out.println("生產:當前剩餘產品-->" + product.getCount()); } } } </span>
3.消費者類,消費者類也實現了Runnable介面。
<span style="font-size:18px;">public class Saler implements Runnable {
Product product = new Product();
public Saler(Product product) {
this.product = product;
}
public void run() {
while (true) {
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
product.sale();
System.out.println("消費:當前剩餘產品-->" + product.getCount());
}
}
}
</span>
4.測試程式碼如下,在測試程式碼中,分別建立了四個生產者執行緒和兩個消費者執行緒。<span style="font-size:18px;">public class Test {
public static void main(String[] args) {
Product product = new Product();
Maker maker = new Maker(product);
Saler saler = new Saler(product);
Thread m1 = new Thread(maker);
Thread m2 = new Thread(maker);
Thread m3 = new Thread(maker);
Thread m4 = new Thread(maker);
Thread s1 = new Thread(saler);
Thread s2 = new Thread(saler);
m1.start();
m2.start();
m3.start();
m4.start();
s1.start();
s2.start();
}
}
</span>
5.執行結果如果下,執行結果中我們可以看到,生產者生產商品的數量,不會超過10個,當商品數量超過10個的時候,生產者就會停止生產,而是等待消費者消費了一定量的商品,才會繼續生產。同樣,當剩餘商品的數量小於0時,消費者也不會繼續消費。這就實現了生產者與消費者間的執行緒通訊,兩者共享一個數據物件。