Java 多線程有序執(zhí)行的幾種方法總結(jié)
Java 多線程有序執(zhí)行的幾種方法總結(jié)
同事無意間提出了這個問題,親自實踐了兩種方法。當(dāng)然肯定還會有更多更好的方法。
方法一
import java.util.concurrent.atomic.AtomicInteger;
public class OrderedThread1 {
static AtomicInteger count = new AtomicInteger(0);
public static void main(String[] args) throws InterruptedException {
Task task1 = new Task(count, 0);
Task task2 = new Task(count, 1);
Task task3 = new Task(count, 2);
Thread thread1 = new Thread(task1);
Thread thread2 = new Thread(task2);
Thread thread3 = new Thread(task3);
thread1.setDaemon(true);
thread2.setDaemon(true);
thread3.setDaemon(true);
thread1.start();
thread2.start();
thread3.start();
Thread.sleep(1 * 1000);
}
}
class Task implements Runnable {
private AtomicInteger count;
private int order;
public Task(AtomicInteger count, int order) {
this.count = count;
this.order = order;
}
@Override
public void run() {
while (true) {
if (count.get() % 3 == order) {
System.out.println(Thread.currentThread().getName() + " ===== "+ order);
count.incrementAndGet();
}
}
}
}
這種方法應(yīng)該是比較常見的解決方案。利用原子遞增控制線程準(zhǔn)入順序。
方法二
public class OrderedThread2 {
static Holder holder = new Holder();
public static void main(String[] args) throws InterruptedException {
Task1 task1 = new Task1(holder, 0);
Task1 task2 = new Task1(holder, 1);
Task1 task3 = new Task1(holder, 2);
Thread thread1 = new Thread(task1);
Thread thread2 = new Thread(task2);
Thread thread3 = new Thread(task3);
thread1.setDaemon(true);
thread2.setDaemon(true);
thread3.setDaemon(true);
thread1.start();
thread2.start();
thread3.start();
Thread.sleep(1 * 1000);
}
}
class Task1 implements Runnable {
Holder holder;
int order;
public Task1(Holder holder, int order) {
this.holder = holder;
this.order = order;
}
@Override
public void run() {
while (true) {
if (holder.count % 3 == order) {
System.out.println(Thread.currentThread().getName() + " ===== "+ order);
holder.count ++;
}
}
// int i = 0;
// while(i ++ < 10000){
// holder.count ++;
// }
}
}
class Holder {
volatile int count = 0;
}
方法二使用了volatile關(guān)鍵字。讓每個線程都能拿到最新的count的值,當(dāng)其中一個線程執(zhí)行++操作后,其他兩個線程就會拿到最新的值,并檢查是否符合準(zhǔn)入條件。
ps:volatile不是線程安全的。而且兩者沒有任何關(guān)系。volatile變量不在用戶線程保存副本,因此對所有線程都能提供最新的值。但試想,如果多個線程同時并發(fā)更新這個變量,其結(jié)果也是顯而易見的,最后一次的更新會覆蓋前面所有更新,導(dǎo)致線程不安全。在方法二中,一次只有一個線程滿足準(zhǔn)入條件,因此不存在對變量的并發(fā)更新。volatile的值是最新的與線程安全完全是不相干的,所以不要誤用volatile實現(xiàn)并發(fā)控制。
感謝閱讀,希望能幫助到大家,謝謝大家對本站的支持!
相關(guān)文章
Mybatis關(guān)于動態(tài)排序 #{} ${}問題
這篇文章主要介紹了Mybatis關(guān)于動態(tài)排序 #{} ${}問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-10-10
Java Apache Shiro安全框架快速開發(fā)詳解流程
Apache Shiro是一個強(qiáng)大且易用的Java安全框架,執(zhí)行身份驗證、授權(quán)、密碼和會話管理。使用Shiro的易于理解的API,您可以快速、輕松地獲得任何應(yīng)用程序,從最小的移動應(yīng)用程序到最大的網(wǎng)絡(luò)和企業(yè)應(yīng)用程序2021-10-10
使用SpringJPA?直接實現(xiàn)count(*)
這篇文章主要介紹了SpringJPA?直接實現(xiàn)count(*),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-11-11
SpringBoot實現(xiàn)二維碼掃碼登錄的原理及項目實踐
本文主要介紹了SpringBoot實現(xiàn)二維碼掃碼登錄的原理及項目實踐,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-04-04
SpringBoot中OKHttp和壓縮文件的使用實戰(zhàn)教程
本文介紹了如何在SpringBoot中使用OKHttp發(fā)起請求和處理壓縮文件,包括文件的存儲配置、實體類、配置類和初始化類的設(shè)置,以及如何通過主程序和測試類進(jìn)行實際操作,最后提供了必要的依賴添加方法,以確保功能的實現(xiàn)2024-10-10

