IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> 【Java面试题】有三个线程 t1,t2,t3,怎么确保它们按顺序执行? -> 正文阅读

[Java知识库]【Java面试题】有三个线程 t1,t2,t3,怎么确保它们按顺序执行?

方案有四:

  1. 【抛弃系列,最low】【线程 t1】代码执行完,调用【线程t2】的start()方法,【t2】执行完调用【线程t3】的start()方法;
  2. 使用线程间通信,3个线程使用同一把锁,【线程t1】执行完后,使用 JUC 中 signal()/signalAll() 方法唤醒【线程t2】,以此类推;
  3. 【推荐使用】 使用线程为我们提供的 join() 方法;
  4. 使用 LockSupport 类的 park()unpark(Thread thread) 方法。

备注:
??代码中使用 sleep() 也是为了更方便复现问题

方案一

??【抛弃系列,最low】方案一是最 low 的一种方式,不做介绍,不建议使用!!!【最终执行顺序:main > t1 > t2 > t3 】

public class SortThread1 {

    public static void main(String[] args) throws InterruptedException {
        
        Thread t3 = new Thread(() -> {
            try {
                TimeUnit.SECONDS.sleep(1);
                System.out.println(Thread.currentThread().getName() + "线程执行完毕");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "t3");


        Thread t2 = new Thread(() -> {
            try {
                TimeUnit.SECONDS.sleep(3);
                System.out.println(Thread.currentThread().getName() + "线程执行完毕");
                // 执行线程3
                t3.start();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "t2");

        Thread t1 = new Thread(() -> {
            try {
                TimeUnit.SECONDS.sleep(2);
                System.out.println(Thread.currentThread().getName() + "线程执行完毕");
                // 执行线程2
                t2.start();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },"t1");

        // 执行线程1
        t1.start();
        
        System.out.println("main 主线程");
    }
}
方案二

??采用线程间通信。三个线程同时启动,使用一把锁。三个线程 t1,t2,t3,按顺序执行,线程 t1 执行完成后,通知线程 t2 ,t2 获取锁后,继续执行,以此类推。【最终执行顺序:t1 > t2 > t3 > main】

public class SortThread2 {

    // 执行的线程(使用volatile修饰保证可见性)
    private volatile static int threadNo = 1;

    public static void main(String[] args) throws InterruptedException {

        // 创建Lock锁
        Lock lock = new ReentrantLock();

        Condition condition1 = lock.newCondition(); // 线程1
        Condition condition2 = lock.newCondition(); // 线程2
        Condition condition3 = lock.newCondition(); // 线程3
        Condition condition4 = lock.newCondition(); // main线程

        /**
         * 线程1
         */
        Thread t1 = new Thread(() -> {
            // 加锁
            lock.lock();
            try {
                while (threadNo != 1) {
                    condition1.await();
                }
                TimeUnit.SECONDS.sleep(2);
                System.out.println(Thread.currentThread().getName() + "线程执行完毕");
                // 修改属性值为2
                threadNo = 2;
                // 唤醒t2线程
                condition2.signal();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                // 释放锁
                lock.unlock();
            }
        }, "t1");

        /**
         * 线程2
         */
        Thread t2 = new Thread(() -> {
            // 加锁
            lock.lock();
            try {
                while (threadNo != 2) {
                    condition2.await();
                }
                TimeUnit.SECONDS.sleep(3);
                System.out.println(Thread.currentThread().getName() + "线程执行完毕");
                // 修改属性值为3
                threadNo = 3;
                // 唤醒t3线程
                condition3.signal();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                // 释放锁
                lock.unlock();
            }
        }, "t2");

        /**
         * 线程3
         */
        Thread t3 = new Thread(() -> {
            // 加锁
            lock.lock();
            try {
                while (threadNo != 3) {
                    condition3.await();
                }
                TimeUnit.SECONDS.sleep(1);
                System.out.println(Thread.currentThread().getName() + "线程执行完毕");
                // 主线程
                threadNo = 4;
                condition4.signal();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                // 释放锁
                lock.unlock();
            }
        }, "t3");

        // 启动线程
        t3.start();
        t2.start();
        t1.start();

        /**
         * main主线程
         */
        // 加锁
        lock.lock();
        while (threadNo != 4) {
            condition4.await();
        }
        System.out.println("main主线程");
    }
}
方案三

??【推荐使用】使用线程为我们提供的 join() 方法。join() 方法会等待当前线程,join(0)则会一直等待线程死亡。join() 和 join(long millis) 方法源码,如下图所示:

在这里插入图片描述
在这里插入图片描述
【最终执行顺序:t1 > t2 > t3 > main】

public class SortThread3 {

    public static void main(String[] args) throws InterruptedException {

        Thread t1 = new Thread(() -> {
            try {
                TimeUnit.SECONDS.sleep(2);
                System.out.println(Thread.currentThread().getName() + "线程执行完毕");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },"t1");

        Thread t2 = new Thread(() -> {
            try {
                TimeUnit.SECONDS.sleep(3);
                System.out.println(Thread.currentThread().getName() + "线程执行完毕");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "t2");

        Thread t3 = new Thread(() -> {
            try {
                TimeUnit.SECONDS.sleep(1);
                System.out.println(Thread.currentThread().getName() + "线程执行完毕");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "t3");

        t1.start();
        t1.join();   // 一直等待t1执行,线程死亡后,执行线程t2
        t2.start();
        t2.join();   // 一直等待t2执行,线程死亡后,执行线程t3
        t3.start();
        t3.join();   // 一直等待t3执行,线程死亡后,执行主线程
        System.out.println("main主线程");
 		//  使用带参数join()方法
        // t1.start();
        // t1.join(10);  // 等待t1线程10ms,t1线程代码内sleep 2s,则不再继续等待t1,执行t2线程
		// t2.start();
		// t2.join(10);  // 等待t2线程10ms,t2线程代码内sleep 3s,则不再继续等待t2,执行t2线程
		// t3.start();
		// t3.join(10);  // 等待t3线程10ms,t3线程代码内sleep 1s.因为 sleep 等待时间原因,最终输出结果是:【t3执行 > t1执行 > t2执行 > main主线程】
    }
}
方案四

??LockSupport.park() 阻塞当前线程,LockSupport.unpark(Thread thread) 唤醒指定线程。LockSupport 属于偏底层方法,了解 LockSupport 的可以来这里查看一下【线程六大状态图:https://blog.csdn.net/lzb348110175/article/details/103579044】,更多请自行百度。【最终执行顺序:t1 > t2 > t3 > main】

public class SortThread4 {

    // main主线程
    private static Thread main = Thread.currentThread();

    public static void main(String[] args) throws InterruptedException {

        Thread t3 = new Thread(() -> {
            try {
                // 阻塞线程
                LockSupport.park();
                TimeUnit.SECONDS.sleep(1);
                System.out.println(Thread.currentThread().getName() + "线程执行完毕");
                // 唤醒main主线程
                LockSupport.unpark(main);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "t3");

        Thread t2 = new Thread(() -> {
            try {
                // 阻塞线程
                LockSupport.park();
                TimeUnit.SECONDS.sleep(3);
                System.out.println(Thread.currentThread().getName() + "线程执行完毕");
                // 唤醒t3主线程
                LockSupport.unpark(t3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "t2");

        Thread t1 = new Thread(() -> {
            try {
                TimeUnit.SECONDS.sleep(2);
                System.out.println(Thread.currentThread().getName() + "线程执行完毕");
                // 唤醒t2主线程
                LockSupport.unpark(t2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },"t1");

        // 执行线程1
        t1.start();
        t2.start();
        t3.start();
        // 阻塞main线程
        LockSupport.park(t1);
        System.out.println("main主线程");
    }

}

博主写作不易,加个关注呗

求关注、求点赞,加个关注不迷路 ヾ(?°?°?)ノ゙

我不能保证所写的内容都正确,但是可以保证不复制、不粘贴。保证每一句话、每一行代码都是亲手敲过的,错误也请指出,望轻喷 Thanks?(・ω・)ノ

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2021-11-05 13:47:57  更:2021-11-05 13:48:00 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 23:41:53-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码