有三个线程T1、T2、T3,如何保证顺序执行?

 作者简介:大家好,我是码炫码哥,前中兴通讯、美团架构师,现任某互联网公司CTO,兼职码炫课堂主讲源码系列专题


代表作:《jdk源码&多线程&高并发》,《深入tomcat源码解析》,《深入netty源码解析》,《深入dubbo源码解析》,《深入springboot源码解析》,《深入spring源码解析》,《深入redis源码解析》等


联系qq:184480602,加我进群,大家一起学习,一起进步,一起对抗互联网寒冬。码炫课堂的个人空间-码炫码哥个人主页-面试,源码等

回答

要想保证 T1T2T3 顺序执行,有多种方法。我们先新建一个 Tread:

class MyThread extends Thread {
    private String threadName;

    public MyThread(String name) {
        this.threadName = name;
    }

    @Override
    public void run() {
        System.out.println(threadName + " is running");
    }
}

一、使用 join()

join() 是 Java 提供的一种用于线程同步的机制,它能够让一个线程等待另一个线程完成后再继续执行。它有三个重载方法:

  1. join():无限等待,直到目标线程执行完毕。
  2. join(long millis):等待目标线程执行完毕,或者达到指定的毫秒时间。
  3. join(long millis, int nanos):等待目标线程执行完毕,或者达到指定的时间(以毫秒和纳秒为单位)。

使用 join() 来实现 T1T2T3 顺序执行,非常简单:

public class JoinTest {
    public static void main(String[] args) {
        MyThread T1 = new MyThread("T1");
        MyThread T2 = new MyThread("T2");
        MyThread T3 = new MyThread("T3");

        try {
            T1.start();
            T1.join(); // 等待 T1 执行完毕

            T2.start();
            T2.join(); // 等待 T2 执行完毕

            T3.start();
            T3.join(); // 等待 T3 执行完毕
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

// 执行结果
T1 is running
T2 is running
T3 is running

方法二:CountDownLatch

CountDownLatch 是一个同步辅助类,它允许一个或多个线程等待,直到在其他线程中执行的一组操作完成。

CountDownLatch 内部是通过一个计数器来实现的,当我们在构造一个CountDownLatch对象的时候需要传 入该计数器值,该值就表示了线程的数量。当一个线程完成自己的任务后,计数器的值就会减1。当计数器的值变为0时,就表示所有的线程均已经完成了任务,然后就可以恢复等待的线程继续执行了。

使用 CountDownLatch 来实现 T1T2T3 顺序执行,如下 :

class MyThread extends Thread {
    private String threadName;
    private CountDownLatch currentLatch;
    private CountDownLatch nextLatch;

    public MyThread(String name, CountDownLatch currentLatch, CountDownLatch nextLatch) {
        this.threadName = name;
        this.currentLatch = currentLatch;
        this.nextLatch = nextLatch;
    }

    @Override
    public void run() {
        try {
            currentLatch.await(); // 等待当前的 CountDownLatch 减到 0
            System.out.println(threadName + " is running.");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            nextLatch.countDown(); // 减少下一个 CountDownLatch 的计数
        }
    }
}

public class CountDownLatchTest {
    public static void main(String[] args) {
        CountDownLatch latch1 = new CountDownLatch(1);
        CountDownLatch latch2 = new CountDownLatch(1);
        CountDownLatch latch3 = new CountDownLatch(1);

        MyThread T1 = new MyThread("T1", latch1, latch2);
        MyThread T2 = new MyThread("T2", latch2, latch3);
        MyThread T3 = new MyThread("T3", latch3, new CountDownLatch(0));

        T1.start();
        T2.start();
        T3.start();
        
        latch1.countDown(); // 启动 T1,计数 -1 变为 0
    }
}

在这里,我们创建了三个 CountDownLatch,分别用于控制 T1T2T3 的启动顺序。每个线程在启动前都等待当前的 CountDownLatch 变为 0,然后执行任务,并减少下一个 CountDownLatch 的计数。

当三个线程启动时,都会在那里等待,T1 等待latch1 变成 0T2 等待latch2 变成 0T3 等待latch3 变成 0。当在 main() 中执行 latch1.countDown() 时,T1 则启动执行,执行完成后执行 latch2.countDown() 驱动 T3 执行。

方案三 :Semaphore

Semaphore 是一个计数信号量,最常用于限制某个资源可被同时访问的线程数。

Semaphore是一个非负整数(>=1)。当一个线程想要访问某个共享资源时,它必须要先获取Semaphore,当Semaphore > 0时,获取该资源并使Semaphore – 1。如果Semaphore = 0,则表示全部的共享资源已经被其他线程全部占用,线程必须要等待其他线程释放资源。当线程释放资源时,Semaphore +1

使用 Semaphore 来实现 T1T2T3 顺序执行,如下 :

class MyThread extends Thread {
    private String threadName;
    private Semaphore currentSemaphore;
    private Semaphore nextSemaphore;

    public MyThread(String name, Semaphore currentSemaphore, Semaphore nextSemaphore) {
        this.threadName = name;
        this.currentSemaphore = currentSemaphore;
        this.nextSemaphore = nextSemaphore;
    }

    @Override
    public void run() {
        try {
            currentSemaphore.acquire(); // 获取当前的 Semaphore 许可
            System.out.println(threadName + " is running.");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            nextSemaphore.release(); // 释放下一个 Semaphore 的许可
        }
    }
}

public class SemaphoreTest {
    public static void main(String[] args) {
        Semaphore semaphore1 = new Semaphore(1); // 初始信号量许可为 1
        Semaphore semaphore2 = new Semaphore(0); // 初始信号量许可为 0
        Semaphore semaphore3 = new Semaphore(0); // 初始信号量许可为 0

        MyThread T1 = new MyThread("T1", semaphore1, semaphore2);
        MyThread T2 = new MyThread("T2", semaphore2, semaphore3);
        MyThread T3 = new MyThread("T3", semaphore3, new Semaphore(0));

        T1.start();
        T2.start();
        T3.start();
    }
}

创建三个 Semaphore 实例,第一个的许可数为 1,其他两个为 0。每个线程在启动前都获取当前的 Semaphore 许可,执行任务后释放下一个 Semaphore 的许可。

最后,其实实现 T1T2T3 的方式有很多种,比如最笨的方式直接使用 wait() 就可以了,T1 wait(10)T2 wait(20)、T3 wait(30),一样可以得到。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值