Java 多線程有序執(zhí)行的幾種方法總結(jié)
Java 多線程有序執(zhí)行的幾種方法總結(jié)
同事無(wú)意間提出了這個(gè)問(wèn)題,親自實(shí)踐了兩種方法。當(dāng)然肯定還會(huì)有更多更好的方法。
方法一
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)該是比較常見(jiàn)的解決方案。利用原子遞增控制線程準(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)鍵字。讓每個(gè)線程都能拿到最新的count的值,當(dāng)其中一個(gè)線程執(zhí)行++操作后,其他兩個(gè)線程就會(huì)拿到最新的值,并檢查是否符合準(zhǔn)入條件。
ps:volatile不是線程安全的。而且兩者沒(méi)有任何關(guān)系。volatile變量不在用戶線程保存副本,因此對(duì)所有線程都能提供最新的值。但試想,如果多個(gè)線程同時(shí)并發(fā)更新這個(gè)變量,其結(jié)果也是顯而易見(jiàn)的,最后一次的更新會(huì)覆蓋前面所有更新,導(dǎo)致線程不安全。在方法二中,一次只有一個(gè)線程滿足準(zhǔn)入條件,因此不存在對(duì)變量的并發(fā)更新。volatile的值是最新的與線程安全完全是不相干的,所以不要誤用volatile實(shí)現(xiàn)并發(fā)控制。
感謝閱讀,希望能幫助到大家,謝謝大家對(duì)本站的支持!
相關(guān)文章
Mybatis關(guān)于動(dòng)態(tài)排序 #{} ${}問(wèn)題
這篇文章主要介紹了Mybatis關(guān)于動(dòng)態(tài)排序 #{} ${}問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-10-10
Java Apache Shiro安全框架快速開(kāi)發(fā)詳解流程
Apache Shiro是一個(gè)強(qiáng)大且易用的Java安全框架,執(zhí)行身份驗(yàn)證、授權(quán)、密碼和會(huì)話管理。使用Shiro的易于理解的API,您可以快速、輕松地獲得任何應(yīng)用程序,從最小的移動(dòng)應(yīng)用程序到最大的網(wǎng)絡(luò)和企業(yè)應(yīng)用程序2021-10-10
使用SpringJPA?直接實(shí)現(xiàn)count(*)
這篇文章主要介紹了SpringJPA?直接實(shí)現(xiàn)count(*),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-11-11
Java Http多次請(qǐng)求復(fù)用同一連接示例詳解
這篇文章主要為大家介紹了Java Http多次請(qǐng)求復(fù)用同一連接示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-10-10
SpringBoot實(shí)現(xiàn)二維碼掃碼登錄的原理及項(xiàng)目實(shí)踐
本文主要介紹了SpringBoot實(shí)現(xiàn)二維碼掃碼登錄的原理及項(xiàng)目實(shí)踐,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-04-04
SpringBoot中OKHttp和壓縮文件的使用實(shí)戰(zhàn)教程
本文介紹了如何在SpringBoot中使用OKHttp發(fā)起請(qǐng)求和處理壓縮文件,包括文件的存儲(chǔ)配置、實(shí)體類(lèi)、配置類(lèi)和初始化類(lèi)的設(shè)置,以及如何通過(guò)主程序和測(cè)試類(lèi)進(jìn)行實(shí)際操作,最后提供了必要的依賴添加方法,以確保功能的實(shí)現(xiàn)2024-10-10

