Java之多個線程順序循環(huán)執(zhí)行的幾種實現(xiàn)
ReentrantLock+Condition方式實現(xiàn)
public class ReentrantLock_Impl { private static final String FLAG_THREAD_1 = "ReentrantLock_Thread1"; private static final String FLAG_THREAD_2 = "ReentrantLock_Thread2"; private static final String FLAG_THREAD_3 = "ReentrantLock_Thread3"; public static void main(String[] args) throws InterruptedException { //ReentrantLock構(gòu)造方法傳入true為公平鎖 false為非公平鎖 ReentrantLock lock = new ReentrantLock(true); Condition condition1 = lock.newCondition(); Condition condition2 = lock.newCondition(); Condition condition3 = lock.newCondition(); FairRunnable runnable = new FairRunnable(lock, condition1, condition2, condition3); new Thread(runnable, FLAG_THREAD_1).start(); new Thread(runnable, FLAG_THREAD_2).start(); new Thread(runnable, FLAG_THREAD_3).start(); } static class FairRunnable implements Runnable { private ReentrantLock lock; private Condition condition1; private Condition condition2; private Condition condition3; public FairRunnable(ReentrantLock lock, Condition condition1, Condition condition2, Condition condition3) { this.lock = lock; this.condition1 = condition1; this.condition2 = condition2; this.condition3 = condition3; } @Override public void run() { while (true) { try { lock.lock(); System.out.println(Thread.currentThread().getName() + "開始執(zhí)行"); Thread.sleep(1000); switch (Thread.currentThread().getName()) { case FLAG_THREAD_1: //喚醒線程2 自身線程掛起阻塞 condition2.signal(); condition1.await(); break; case FLAG_THREAD_2: //喚醒線程3 自身線程掛起阻塞 condition3.signal(); condition2.await(); break; case FLAG_THREAD_3: //喚醒線程1 自身線程掛起阻塞 condition1.signal(); condition3.await(); break; } } catch (Exception e) { e.printStackTrace(); return; } finally { lock.unlock(); } } } } }
執(zhí)行結(jié)果:
ReentrantLock_Thread1開始執(zhí)行
ReentrantLock_Thread2開始執(zhí)行
ReentrantLock_Thread3開始執(zhí)行
ReentrantLock_Thread1開始執(zhí)行
ReentrantLock_Thread2開始執(zhí)行
ReentrantLock_Thread3開始執(zhí)行
......
Synchronized+wait/notifyAll方式實現(xiàn)
public class Synchronized_Impl { private static final String FLAG_THREAD_1 = "Synchronized_Thread1"; private static final String FLAG_THREAD_2 = "Synchronized_Thread2"; private static final String FLAG_THREAD_3 = "Synchronized_Thread3"; public static void main(String[] args) { FairRunnable runnable = new FairRunnable(); new Thread(runnable, FLAG_THREAD_1).start(); new Thread(runnable, FLAG_THREAD_2).start(); new Thread(runnable, FLAG_THREAD_3).start(); } static class FairRunnable implements Runnable { private volatile static int flag = 1; private final Object object = new Object(); @Override public void run() { while (true) { synchronized (object) { //如果當(dāng)前情況是:線程1&flag!=1、線程2&flag!=2、線程3&flag!=3 那當(dāng)前線程通過object.wait掛起 switch (Thread.currentThread().getName()) { case FLAG_THREAD_1: while (flag != 1) { try { object.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } break; case FLAG_THREAD_2: while (flag != 2) { try { object.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } break; case FLAG_THREAD_3: while (flag != 3) { try { object.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } break; } //線程任務(wù)開始執(zhí)行 System.out.println(Thread.currentThread().getName() + "開始執(zhí)行"); try { //模擬線程任務(wù)執(zhí)行 Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); break; } switch (Thread.currentThread().getName()) { case FLAG_THREAD_1: //接下來該去執(zhí)行線程2 flag = 2; break; case FLAG_THREAD_2: //接下來該去執(zhí)行線程3 flag = 3; break; case FLAG_THREAD_3: //接下來該去執(zhí)行線程1 flag = 1; break; } //喚醒所有線程 object.notifyAll(); } } } } }
執(zhí)行結(jié)果:
Synchronized_Thread1開始執(zhí)行
Synchronized_Thread2開始執(zhí)行
Synchronized_Thread3開始執(zhí)行
Synchronized_Thread1開始執(zhí)行
Synchronized_Thread2開始執(zhí)行
Synchronized_Thread3開始執(zhí)行
......
兩者對比
使用ReentrantLock+Condition可以更準(zhǔn)確的控制喚醒哪一個線程;
而Synchronized+wait/notifyAll的方式可能會出現(xiàn)獲取鎖的線程并不是目標(biāo)線程,此時獲取鎖的線程會重新掛起,直到獲取鎖的線程即是目標(biāo)線程為止。
比如上面代碼中:
線程1執(zhí)行完后調(diào)用notifyAll(), 此時線程2、線程3都會被喚醒并嘗試獲取鎖,如果此時線程3獲得鎖,那么線程2還要繼續(xù)等待,線程3執(zhí)行時發(fā)現(xiàn)并不是要執(zhí)行的目標(biāo)線程,那么線程3會調(diào)用wait()掛起,此時entrySet中只有線程2了,線程2也是要執(zhí)行的目標(biāo)線程,此時才會去執(zhí)行線程2,整個過程多了一次線程3的獲取與釋放鎖,原因就是wait/notifyAll并不能像ReentrantLock+Condition一樣能精確地喚醒某個線程。
總結(jié)
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
SpringBoot集成Zipkin實現(xiàn)分布式全鏈路監(jiān)控
這篇文章主要介紹了SpringBoot集成Zipkin實現(xiàn)分布式全鏈路監(jiān)控的方法啊,本文通過實例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價值,需要的朋友可以參考下2019-09-09Java基于rest assured實現(xiàn)接口測試過程解析
這篇文章主要介紹了Java基于rest assured實現(xiàn)接口測試過程解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-03-03使用Java實現(xiàn)創(chuàng)建Excel表單控件
在數(shù)據(jù)填報時,創(chuàng)建Excel表單控件是一項常見的任務(wù),它可以極大地簡化數(shù)據(jù)收集和處理的過程,本文主要介紹了如何使用Java實現(xiàn)創(chuàng)建Excel表單控件,感興趣的可以了解下2024-03-03