亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Java中保證線程順序執(zhí)行的操作代碼

 更新時間:2021年05月15日 09:21:00   作者:六層樓  
本文給大家分享一篇教程關于java線程順序執(zhí)行問題,如何保證線程的順序執(zhí)行呢?今天通過實例代碼給大家詳細講解下,感興趣的朋友跟隨小編一起看看吧

只要了解過多線程,我們就知道線程開始的順序跟執(zhí)行的順序是不一樣的。如果只是創(chuàng)建三個線程然后執(zhí)行,最后的執(zhí)行順序是不可預期的。這是因為在創(chuàng)建完線程之后,線程執(zhí)行的開始時間取決于CPU何時分配時間片,線程可以看成是相對于的主線程的一個異步操作。

public class FIFOThreadExample {
    public synchronized static void foo(String name) {
        System.out.print(name);
    }

    public static void main(String[] args) {
        Thread thread1 = new Thread(() -> foo("A"));
        Thread thread2 = new Thread(() -> foo("B"));
        Thread thread3 = new Thread(() -> foo("C"));
        thread1.start();
        thread2.start();
        thread3.start();
    }
}

輸出結(jié)果:ACB/ABC/CBA...

那么我們該如何保證線程的順序執(zhí)行呢?

如何保證線程的順序執(zhí)行?

1. 使用Thread.join()實現(xiàn)

Thread.join()的作用是讓父線程等待子線程結(jié)束之后才能繼續(xù)運行。以上述例子為例,main()方法所在的線程是父線程,在其中我們創(chuàng)建了3個子線程A,B,C,子線程的執(zhí)行相對父線程是異步的,不能保證順序性。而對子線程使用Thread.join()方法之后就可以讓父線程等待子線程運行結(jié)束后,再開始執(zhí)行父線程,這樣子線程執(zhí)行被強行變成了同步的,我們用Thread.join()方法就能保證線程執(zhí)行的順序性。

public class FIFOThreadExample {
    
    public static void foo(String name) {
        System.out.print(name);
    }

    public static void main(String[] args) throws InterruptedException{
        Thread thread1 = new Thread(() -> foo("A"));
        Thread thread2 = new Thread(() -> foo("B"));
        Thread thread3 = new Thread(() -> foo("C"));
        thread1.start();
        thread1.join();
        thread2.start();
        thread2.join();
        thread3.start();
    }
}

輸出結(jié)果:ABC

2. 使用單線程線程池來實現(xiàn)

另一種保證線程順序執(zhí)行的方法是使用一個單線程的線程池,這種線程池中只有一個線程,相應的,內(nèi)部的線程會按加入的順序來執(zhí)行。

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class FIFOThreadExample {

    public static void foo(String name) {
        System.out.print(name);
    }

    public static void main(String[] args) throws InterruptedException{
        Thread thread1 = new Thread(() -> foo("A"));
        Thread thread2 = new Thread(() -> foo("B"));
        Thread thread3 = new Thread(() -> foo("C"));
        ExecutorService executor = Executors.newSingleThreadExecutor();
        executor.submit(thread1);
        executor.submit(thread2);
        executor.submit(thread3);
        executor.shutdown();
    }
}

輸出結(jié)果:ABC

3. 使用volatile關鍵字修飾的信號量實現(xiàn)

上面兩種的思路都是讓保證線程的執(zhí)行順序,讓線程按一定的順序執(zhí)行。這里介紹第三種思路,那就是線程可以無序運行,但是執(zhí)行結(jié)果按順序執(zhí)行。
你應該可以想到,三個線程都被創(chuàng)建并start(),這時候三個線程隨時都可能執(zhí)行run()方法。因此為了保證run()執(zhí)行的順序性,我們肯定需要一個信號量來讓線程知道在任意時刻能不能執(zhí)行邏輯代碼。
另外,因為三個線程是獨立的,這個信號量的變化肯定需要對其他線程透明,因此volatile關鍵字也是必須要的。

public class TicketExample2 {

    //信號量
    static volatile int ticket = 1;
    //線程休眠時間
    public final static int SLEEP_TIME = 1;

    public static void foo(int name){
        //因為線程的執(zhí)行順序是不可預期的,因此需要每個線程自旋
        while (true) {
            if (ticket == name) {
                try {
                    Thread.sleep(SLEEP_TIME);
                    //每個線程循環(huán)打印3次
                    for (int i = 0; i < 3; i++) {
                        System.out.println(name + " " + i);
                    }

                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //信號量變更
                ticket = name%3+1;
                return;

            }
        }
    }
    public static void main(String[] args) throws InterruptedException {
        Thread thread1 = new Thread(() -> foo(1));
        Thread thread2 = new Thread(() -> foo(2));
        Thread thread3 = new Thread(() -> foo(3));
        thread1.start();
        thread2.start();
        thread3.start();
    }
}

執(zhí)行結(jié)果:
1 0
1 1
1 2
2 0
2 1
2 2
3 0
3 1
3 2

4. 使用Lock和信號量實現(xiàn)

此種方法的思想跟第三種方法是一樣的,都是不考慮線程執(zhí)行的順序而是考慮用一些方法控制線程執(zhí)行業(yè)務邏輯的順序。這里我們同樣用一個原子類型信號量ticket,當然你可以不用原子類型,這里我只是為了保證自增操作的線程安全。然后我們用了一個可重入鎖ReentrantLock。用來給方法加鎖,當一個線程拿到鎖并且標識位正確的時候開始執(zhí)行業(yè)務邏輯,執(zhí)行完畢后喚醒下一個線程。
這里我們不需要使用while進行自旋操作了,因為Lock可以讓我們喚醒指定的線程,所以改成if就可以實現(xiàn)順序的執(zhí)行。

public class TicketExample3 {
    //信號量
    AtomicInteger ticket = new AtomicInteger(1);
    public Lock lock = new ReentrantLock();
    private Condition condition1 = lock.newCondition();
    private Condition condition2 = lock.newCondition();
    private Condition condition3 = lock.newCondition();
    private Condition[] conditions = {condition1, condition2, condition3};

    public void foo(int name) {
        try {
            lock.lock();
            //因為線程的執(zhí)行順序是不可預期的,因此需要每個線程自旋
            System.out.println("線程" + name + " 開始執(zhí)行");
            if(ticket.get() != name) {
                try {
                    System.out.println("當前標識位為" + ticket.get() + ",線程" + name + " 開始等待");
                    //開始等待被喚醒
                    conditions[name - 1].await();
                    System.out.println("線程" + name + " 被喚醒");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println(name);
            ticket.getAndIncrement();
            if (ticket.get() > 3) {
                ticket.set(1);
            }
            //執(zhí)行完畢,喚醒下一次。1喚醒2,2喚醒3
            conditions[name % 3].signal();
        } finally {
            //一定要釋放鎖
            lock.unlock();
        }

    }

    public static void main(String[] args) throws InterruptedException {
        TicketExample3 example = new TicketExample3();
        Thread t1 = new Thread(() -> {
            example.foo(1);
        });
        Thread t2 = new Thread(() -> {
            example.foo(2);
        });
        Thread t3 = new Thread(() -> {
            example.foo(3);
        });
        t1.start();
        t2.start();
        t3.start();
    }
}

輸出結(jié)果:
線程2 開始執(zhí)行
當前標識位為1,線程2 開始等待
線程1 開始執(zhí)行
1
線程3 開始執(zhí)行
當前標識位為2,線程3 開始等待
線程2 被喚醒
2
線程3 被喚醒
3

上述的執(zhí)行結(jié)果并非唯一,但可以保證打印的順序一定是123這樣的順序。

參考文章

java 多線程 實現(xiàn)多個線程的順序執(zhí)行 - Hoonick - 博客園 (cnblogs.com)
Java lock鎖的一些細節(jié)_筆記小屋-CSDN博客
VolatileCallSite (Java Platform SE 8 ) (oracle.com)
java保證多線程的執(zhí)行順序 - james.yj - 博客園 (cnblogs.com)

以上就是Java中保證線程順序執(zhí)行的詳細內(nèi)容,更多關于java線程執(zhí)行順序的資料請關注腳本之家其它相關文章!

相關文章

  • SpringBoot連接Nacos集群報400問題及完美解決方法

    SpringBoot連接Nacos集群報400問題及完美解決方法

    這篇文章主要介紹了解決SpringBoot連接Nacos集群報400問題?,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-02-02
  • Java基礎類之ArrayUtils工具類詳解

    Java基礎類之ArrayUtils工具類詳解

    這篇文章主要介紹了java.ArrayDeque類使用方法,java.ArrayDeque類提供了可調(diào)整大小的陣列,并實現(xiàn)了Deque接口,感興趣的小伙伴們可以參考一下
    2021-09-09
  • SpringSecurity整合Jwt過程圖解

    SpringSecurity整合Jwt過程圖解

    這篇文章主要介紹了SpringSecurity整合Jwt過程圖解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-01-01
  • SpringBoot+layuimini實現(xiàn)左側(cè)菜單動態(tài)展示的示例代碼

    SpringBoot+layuimini實現(xiàn)左側(cè)菜單動態(tài)展示的示例代碼

    Layuimini是Layui的升級版,它是專業(yè)做后臺頁面的框架,而且是適合PC端和移動端,以下地址可以在PC端顯示,也可以在手機上顯示,只不過會做自適應,本文將給大家介紹了SpringBoot+layuimini實現(xiàn)左側(cè)菜單動態(tài)展示的方法,需要的朋友可以參考下
    2024-04-04
  • 高并發(fā)下restTemplate的錯誤分析方式

    高并發(fā)下restTemplate的錯誤分析方式

    這篇文章主要介紹了高并發(fā)下restTemplate的錯誤分析方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-10-10
  • 基于binarywang封裝的微信工具包生成二維碼

    基于binarywang封裝的微信工具包生成二維碼

    這篇文章主要介紹了基于binarywang封裝的微信工具包生成二維碼,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-11-11
  • Java過濾所有特殊字符的案例

    Java過濾所有特殊字符的案例

    這篇文章主要介紹了Java過濾所有特殊字符的相關資料,包括java中清理所有特殊字符及java正則過濾特殊字符的方法,感興趣的朋友跟隨小編一起看看吧
    2024-02-02
  • Java?FTP協(xié)議實現(xiàn)文件下載功能

    Java?FTP協(xié)議實現(xiàn)文件下載功能

    FTP(File?Transfer?Protocol)就是文件傳輸協(xié)議。通過FTP客戶端從遠程FTP服務器上拷貝文件到本地計算機稱為下載,將本地計算機上的文件復制到遠程FTP服務器上稱為上傳,上傳和下載是FTP最常用的兩個功能
    2022-11-11
  • SpringBoot實現(xiàn)elasticsearch索引操作的代碼示例

    SpringBoot實現(xiàn)elasticsearch索引操作的代碼示例

    這篇文章主要給大家介紹了SpringBoot如何實現(xiàn)elasticsearch 索引操作,文中有詳細的代碼示例,感興趣的同學可以參考閱讀下
    2023-07-07
  • 什么是RESTful?API,有什么作用

    什么是RESTful?API,有什么作用

    提到RESTful?API大家勢必或多或少聽說過,但是什么是RESTful?API??如何理解RESTful?API?呢?今天咱們就來聊聊這個RESTful?API
    2023-11-11

最新評論