有三个线程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),一样可以得到。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值