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知识库 -> 关于Thread线程类中join方法的理解 -> 正文阅读

[Java知识库]关于Thread线程类中join方法的理解

1、案例需求

现有a,b,c三个线程,要求b,c线程必须确保在a执行完成后执行(这里要求用join来完成)

2、案例代码

package com.rcb.edg;

/**
 * @author : jizhuang.wang
 * @version V1.0
 * @Project: hive-udf
 * @Package com.rcb.edg
 * @Description: TODO
 * @date Date : 20220508 12:56
 */
public class SyncTest {
    //此次synchronized锁定的是SyncTest类的实列对象this,而非class类
    public final synchronized void a(int name)  {
        System.out.println("-------开始-------"+name);
        try {
            Thread.sleep(10);
        }catch (InterruptedException e){
            e.printStackTrace();
        }
        System.out.println("--结束--"+name);
    }
    //此次synchronized锁定的是SyncTest.class类,而非对象实例
    public static synchronized void b(int name)  {
        System.out.println("-------开始-------"+name);
        try {
            Thread.sleep(10);
        }catch (InterruptedException e){
            e.printStackTrace();
        }
        System.out.println("--结束--"+name);
    }


    public static void main(String[] args) throws InterruptedException {
            SyncTest o = new SyncTest();

//                new Thread(()->{o.b(3);}).start();
//                new Thread(()->{o.b(4);}).start();



        Thread a = new Thread(() -> new SyncTest().a(1));

        Thread b = new Thread(() -> {
            try {
                //在b线程实例中调用a线程对象实例的join方法,以达到a线程执行完成后在执行b的效果
                //思考下:为什么能确保,执行完a后在执行b这种顺序关系呢?a->b
                //要知道在当前b线程对象中调用a线程对象的join方法,而a对象的join方法是有synchronized修饰关键字锁的,
                //那么就知道这里其实是获取锁了。锁对象就是调用了join方法的那个对象(这里被锁定的对象就是a线程的对象实例)
                //b线程实例获取锁资源后,当前线程条件允许下调用wait()方法,让当前线程(b线程实例)释放锁并挂起线程 即:wait释放了锁后被阻塞
                //补充说明:
                //1.synchronized某个实例方法:主要是获取当前运行对象的Monitor
                //2.synchronized某个静态方法:主要是获取类对象的Monitor
                //3.synchronized方法块:主要获取同步块中对象的Monitor
                //4.获取锁就是获取被锁对象Monitor的_owner所有者权限
                //5.当线程a执行完毕后,jvm在关闭线程之前会检测线阻塞在a线程对象上的线程,然后执行notfyAll(),这样b线程就被唤醒了
                a.join();
                new SyncTest().a(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        Thread c = new Thread(() -> {
            try {
                a.join();//在c线程中调用a.join方法,达到a执行完成后在执行c
                new SyncTest().a(3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        c.start();
        b.start();
        a.start();
        //此处为main线程(调用者)调用a线程(被调用者)的join方法:主线程main,必须在a线程执行完成后在输出
        //但不保证b,c线程先与main线程执行完哦
        a.join();
        System.out.println("main_线程执行结束了");
    }
}

3. join源码片段

   /**
     * 等待该线程终止的时间最长为millis毫秒,超时时间为0意味着要一直等下去
     * @param millis 以毫秒为单位的等待时间
     * @throws InterruptedException
     */
#该方法为synchronized同步关键字修饰
public final synchronized void join(long millis)
    throws InterruptedException {
        long base = System.currentTimeMillis();
        long now = 0;
        //等待时长millis小于0时(负数),报异常
        if (millis < 0) {
            throw new IllegalArgumentException("timeout value is negative");
        }
        //millis等于0时,若当前调用线程是存活的,则线程无限等待,直至被其他线程唤醒
        /**
         例如:在main主线程中调用了线程t1.join()方法,则这里当前线程就是指的main主线程,这里的isAlive()方法,就会校验main线程是否还存活,存活则继续阻塞,或阻塞时间到了从新运行;
         主要:这里wait(0)的是当前的main主线程,t1.join()就是在当前线程中调用的
        **/
        if (millis == 0) {
            while (isAlive()) {
                wait(0);
            }
        } else {
            while (isAlive()) {
                long delay = millis - now;
                if (delay <= 0) {
                    break;
                }
                wait(delay);
                now = System.currentTimeMillis() - base;
            }
        }
    }

4、思考

join执行完后,是如何唤醒阻塞线程的呢?
线程唤醒

我们自己使用都是wait和notify/notifyAll成对出现的。否则线程将无限期等待下去。如果等待线程还是一个非守护线程。那么就会导致程序不能正常结束

当线程t1执行完毕是,jvm在关闭线程之前会检测线阻塞在t1线程对象上的线程,然后执行notfyAll(),这样t2就没唤醒了
理解join必须要理解线程thread、synchronized同步锁的用法及他们的原理哦

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-05-09 12:26:14  更:2022-05-09 12:27:54 
 
开发: 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:55:12-

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