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-09
Java基于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

