[24]多執行緒生產與消費
阿新 • • 發佈:2018-11-12
一、用Synchronized程式碼塊
可以根據註釋閱讀程式碼
run()方法解析
package synchronized_compro; /** * 資源類(因為資源共享,所以要是單例) * 屬性:商品名稱,商品編號,標識,單例引用 * */ public class Resource { private static final Resource r=new Resource(); //單例 private String name; //商品名稱 private int num=1; //商品編號 private boolean flag=false; //標識,用於標識是該生產還是消費 public void setFlag(boolean flag) { this.flag = flag; } public boolean getFlag() { return flag; } public void setName(String name) { this.name = name+num; num++; } public String getName() { return name; } public static Resource getInstance() { return r; } } package synchronized_compro; /** * 生產類(生產一般是多個,所以用執行緒) 屬性:資源的物件引用 行為:生產 */ public class Producer implements Runnable { private Resource r = Resource.getInstance(); // 單例 /* 生產 */ public void set(String name) { r.setName("商品"); System.out.println(Thread.currentThread().getName() + " : 生產 " + r.getName()); } @Override public void run() { // TODO Auto-generated method stub while (true) { synchronized (r) { while (r.getFlag()) { try { r.wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } set("商品"); r.setFlag(true); r.notifyAll(); } } } } package synchronized_compro; /** * 消費類(消費一般是多個,所以用執行緒) * 屬性:資源的物件引用 * 行為:消費 * */ public class Consumer implements Runnable{ private Resource r=Resource.getInstance();//單例 /*消費*/ public void out() { System.out.println(Thread.currentThread().getName()+" : 消費 "+r.getName()); } @Override public void run() { // TODO Auto-generated method stub while (true) { synchronized (r) { while (!r.getFlag()) { try { r.wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } out(); r.setFlag(false); r.notifyAll(); } } } } package synchronized_compro; /** * 測試類 * */ public class Demo { public static void main(String[] args) { Producer p=new Producer(); //例項化生產 Consumer c=new Consumer(); //例項化消費 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(); } }
notifyAll()會造成浪費太多資源,降低效能。notify()會產生死鎖。雖說可以使用兩個synchronized巢狀程式碼塊,但是這樣也會造成死鎖。
二、利用Lock替代synchronized,利用Condition來替代監視器方法
這樣就可以解決只有一個鎖難以解決佔用資源的缺點
package compro; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** * 資源類(因為資源共享,所以要是單例) * 屬性:商品名稱,商品編號 * */ public class Resource { private static final Resource r=new Resource(); //資源 private String name; //商品名稱 private int num=1; //商品編號 private boolean flag=false; //標識,用於標識是該生產還是消費 private static Lock lock=new ReentrantLock(); //鎖例項 private static Condition con1=lock.newCondition(); //生產監視器 private static Condition con2=lock.newCondition(); //消費監視器 public void setFlag(boolean flag) { this.flag = flag; } public boolean getFlag() { return flag; } public void setName(String name) { this.name = name+num; num++; } public String getName() { return name; } /*對外開放能獲取資源物件的方法*/ public static Resource getInstance() { return r; } /*對外開放能獲取Lock物件的方法*/ public static Lock getLock() { return lock; } /*對外開放能獲取Con1物件的方法*/ public static Condition getCon1() { return con1; } /*對外開放能獲取Con2物件的方法*/ public static Condition getCon2() { return con2; } } package compro; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; /** * 生產類(生產一般是多個,所以用執行緒 屬性:資源的物件引用 行為:生產 */ public class Producer implements Runnable { private Resource r = Resource.getInstance(); //資源 private Lock lock = Resource.getLock(); //鎖 private Condition con1 = Resource.getCon1(); //監視器 /* 生產 */ public void set(String name) { r.setName("商品"); System.out.println(Thread.currentThread().getName() + " : 生產 " + r.getName()); } @Override public void run() { // TODO Auto-generated method stub lock.lock(); try { while (true) { while (r.getFlag()) { try { con1.await(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } set("商品"); r.setFlag(true); con1.signal(); } } finally { // TODO: handle finally clause lock.unlock(); } } } package compro; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; /** * 消費類(消費一般是多個,所以用執行緒) * 屬性:資源的物件引用 * 行為:消費 * */ public class Consumer implements Runnable{ private Resource r=Resource.getInstance(); //資源 private Lock lock=Resource.getLock(); //鎖 private Condition con2=Resource.getCon2(); //監視器 /*消費*/ public void out() { System.out.println(Thread.currentThread().getName()+" : 消費 "+r.getName()); } @Override public void run() { // TODO Auto-generated method stub lock.lock(); try { while(true) { while(!r.getFlag()) { try { con2.await(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } out(); r.setFlag(false); con2.signal(); } } finally { // TODO: handle finally clause lock.unlock(); } } } package compro; /** * 測試類 * */ public class Demo { public static void main(String[] args) { Producer p=new Producer(); //例項化生產 Consumer c=new Consumer(); //例項化消費 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(); } }