簡單的執行緒同步問題:兩個執行緒交替執行N次【Synchronized、Lock、ArrayBlockingQueue】

qingyezhu發表於2015-03-21
方法一:傳統的執行緒方法
import
org.apache.log4j.Logger; /** * 兩個執行緒執行的程式碼片段要實現同步互斥的效果,它們必須用同一個Lock物件。<br/> * 鎖是上在代表要操作的資源的類的內部方法中,而不是執行緒程式碼中。<br/> * * 樣例:<br/> * 1)、主執行緒執行10次迴圈,接著子執行緒執行100此迴圈;<br/> * 2)、重複1)操作50次,結束。<br/> * * @author wangzhu * @date 2015-3-21下午8:00:57 * */ public class ThreadCommunication { public static void main(String[] args) { final Bussiness bussiness = new Bussiness(); new Thread() { @Override public void run() { for (int i = 0; i < 50; i++) { bussiness.main(i); } }; }.start(); new Thread() { @Override public void run() { for (int i = 0; i < 50; i++) { bussiness.sub(i); } }; }.start(); } } class Bussiness { private static final Logger logger = Logger.getLogger(Bussiness.class); /** * true:主執行緒<br/> * false:子執行緒<br/> * 預設執行主執行緒<br/> */ private boolean mark = false; public synchronized void main(int c) { while (mark) { // 表示當前是主執行緒,則進入等待狀態 try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } // 當不是主執行緒,則開始執行 for (int i = 0; i < 10; i++) { logger.info(c + "==main thread====" + i); } // 表示當前是主執行緒 mark = true; // 喚醒所有的執行緒 this.notifyAll(); } public synchronized void sub(int c) { while (!mark) { // 表示當前是子執行緒,則進入等待狀態 try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } // 當不是子執行緒,則開始執行 for (int i = 0; i < 100; i++) { logger.info(c + "==sub thread====" + i); } // 表示當前是子執行緒 mark = false; // 喚醒所有的執行緒 this.notifyAll(); } }

 

 

2、JDK1.5之後(包括1.5)加入的併發包(LockCondition
import
java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import org.apache.log4j.Logger; /** * 兩個執行緒執行的程式碼片段要實現同步互斥的效果,它們必須用同一個Lock物件。<br/> * 鎖是上在代表要操作的資源的類的內部方法中,而不是執行緒程式碼中。<br/> * * 樣例:<br/> * 1)、主執行緒執行10次迴圈,接著子執行緒執行100此迴圈;<br/> * 2)、重複1)操作50次,結束。<br/> * * @author wangzhu * @date 2015-3-22下午9:50:11 * */ public class ConditionCommunication { private static final Logger logger = Logger .getLogger(ConditionCommunication.class); /** * @param args */ public static void main(String[] args) { final Bussiness bussiness = new Bussiness(); new Thread() { @Override public void run() { for (int i = 0; i < 50; i++) { bussiness.sub(i); } }; }.start(); new Thread() { @Override public void run() { for (int i = 0; i < 50; i++) { bussiness.main(i); } }; }.start(); } static class Bussiness { private Lock lock = new ReentrantLock(); private Condition condition = lock.newCondition(); /** * true:主執行緒<br/> * false:子執行緒<br/> */ private boolean mark; public void main(int k) { // 加鎖 lock.lock(); try { while (mark) { // 當前是主執行緒,則等待 try { condition.await(); } catch (InterruptedException e) { e.printStackTrace(); } } for (int i = 0; i < 10; i++) { logger.info(k + "==main thread====" + i); } // 標記當前執行的是主執行緒 mark = true; // 發出訊號 condition.signal(); } finally { // 釋放鎖 lock.unlock(); } } public void sub(int k) { // 加鎖 lock.lock(); try { while (!mark) { try { condition.await(); } catch (InterruptedException e) { e.printStackTrace(); } } for (int i = 0; i < 100; i++) { logger.info(k + "==sub thread====" + i); } // 標記當前執行的是子執行緒 mark = false; // 發出訊號 condition.signal(); } finally { // 釋放鎖 lock.unlock(); } } } }

 

 

JDK中的例項:
class
BoundedBuffer { final Lock lock = new ReentrantLock();//鎖物件 final Condition notFull = lock.newCondition();//寫執行緒條件 final Condition notEmpty = lock.newCondition();//讀執行緒條件 final Object[] items = new Object[100];//快取佇列 int putptr/*寫索引*/, takeptr/*讀索引*/, count/*佇列中存在的資料個數*/; public void put(Object x) throws InterruptedException { lock.lock(); try { while (count == items.length)//如果佇列滿了 notFull.await();//阻塞寫執行緒 items[putptr] = x;//賦值 if (++putptr == items.length){ putptr = 0;//如果寫索引寫到佇列的最後一個位置了,那麼置為0 } ++count;//個數++ notEmpty.signal();//喚醒讀執行緒 } finally { lock.unlock(); } } public Object take() throws InterruptedException { lock.lock(); try { while (count == 0)//如果佇列為空 notEmpty.await();//阻塞讀執行緒 Object x = items[takeptr];//取值 if (++takeptr == items.length){ takeptr = 0;//如果讀索引讀到佇列的最後一個位置了,那麼置為0 } --count;//個數-- notFull.signal();//喚醒寫執行緒 return x; } finally { lock.unlock(); } } }

 

參考:

http://blog.csdn.net/vking_wang/article/details/9952063

 

 

3、JDK1.5併發包中的阻塞佇列(ArrayBlockingQueue
import
java.util.concurrent.ArrayBlockingQueue; import org.apache.log4j.Logger; /** * ArrayBlockingQueue(阻塞佇列)<br/> *    put(anObject):<br/> * 把anObject加到BlockingQueue裡,如果BlockQueue沒有空間,<br/> * 則呼叫此方法的執行緒被阻斷,直到BlockingQueue裡面有空間再繼續.<br/> * *   take():<br/> * 取走BlockingQueue裡排在首位的物件,若BlockingQueue為空,<br/> * 阻斷進入等待狀態直到,BlockingQueue有新的資料被加入;<br/> * * @author wangzhu * @date 2015-3-23上午9:31:22 * */ public class ArrayBlockingQueueCommunication { private static final Logger logger = Logger .getLogger(ArrayBlockingQueueCommunication.class); /** * @param args */ public static void main(String[] args) { final Bussiness bussiness = new Bussiness(); new Thread() { @Override public void run() { for (int i = 0; i < 50; i++) { bussiness.sub(i); } }; }.start(); new Thread() { @Override public void run() { for (int i = 0; i < 50; i++) { bussiness.main(i); } }; }.start(); } static class Bussiness { // 阻塞佇列 ArrayBlockingQueue<Integer> mainQuery = new ArrayBlockingQueue<Integer>( 1); ArrayBlockingQueue<Integer> subQuery = new ArrayBlockingQueue<Integer>( 1); { try { subQuery.put(1); } catch (InterruptedException e) { e.printStackTrace(); } } public void main(int k) { try { mainQuery.put(1); } catch (InterruptedException e) { e.printStackTrace(); } for (int i = 0; i < 10; i++) { logger.info(k + "==main thread====" + i); } try { subQuery.take(); } catch (InterruptedException e) { e.printStackTrace(); } } public void sub(int k) { try { subQuery.put(1); } catch (InterruptedException e) { e.printStackTrace(); } for (int i = 0; i < 100; i++) { logger.info(k + "==sub thread====" + i); } try { mainQuery.take(); } catch (InterruptedException e) { e.printStackTrace(); } } } }

參考:

http://www.cnblogs.com/jackyuj/archive/2010/11/24/1886553.html

 

相關文章