首页 > 其他分享 >对线程join()方法的理解

对线程join()方法的理解

时间:2023-08-06 09:11:06浏览次数:43  
标签:join text data 理解 线程 marks nodes type id

java线程的join()方法的理解

thread.join() 把指定的线程加入到当前线程,可以将两个交替执行的线程和并为顺序执行的线程。简单说就是同步
  • 例1:比如在线程B中调用了线程A的 join 方法,直到线程A执行完毕后,才会继续执行线程B。
  • 例2:再比如我们做查询操作,总任务需要返回三个查询列表,那么主线程就需要等待这三个线程全部执行完并返回结果后才可以结束,这时就需要用到 join 方法。(具体例子可以看博客 “线程池怎么用(实例)“)
  • 例3:某些情况、主线程中启用了子线程,如果子线程需要大量的算法,需要运算的时间较长,主线程可能会在子线程结束前就结束,这个时候如果想等待子线程结束后再结束主线程,可以使用join()方法。
 
/**例1**/
t.join();   //调用join方法,等待线程t执行完毕
t.join(1000); //等待 t 线程,等待时间是1000毫秒。
 
/**例3**/
public class JoinTest {
    public static void main(String[] args) throws InterruptedException {
        Thread thread1= new Thread(()->{
            try {
                Thread.sleep(9000);//子线程处理中
                System.out.println("子线程处理完成");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        thread1.start();
        thread1.join();
        System.out.println("主线程结束");
    }
}
  wait(0)这个方法的作用是让当前线程等待一段时间,时间为0表示线程立即进入等待状态。通常情况下,我们会给wait()方法传递一个时间参数,表示让线程等待多少毫秒。但是如果我们传递0或者一个负数,那么线程就会立即进入等待状态,直到被其他线程唤醒。需要注意的是,wait()方法必须在synchronized块中调用。  

join源码解析

看一段JDK提供的源码 0
  • Waits at most millis milliseconds for this thread to die. A timeout of 0 means to wait forever. 意思是等待一段时间直到这个线程死亡。超时0意味着永远等待。
  • 从源码中我们可以看出来join方法的实现是通过wait,wait是一个Object提供的方法。当main线程调用 t.join 时,主线程会获得线程对象的锁(wait意味着拿到该对象的锁),调用该对象的 wait(time) ,直到该对象唤醒main线程。比如退出。这就意味着main 线程调用 t.join时,必须能够拿到线程t对象的锁。如果拿不到时无法wait的。
  这里注意等待线程死亡的意思,是指如果主线程调用 t.join(100) ,那么主线程就要等待 t 线程,等待时间为100ms。 举个例子:
public class JoinTest {
    public static void main(String[] args) {
        Thread t=new Thread(new RunnableImpl());
        t.start();
        try {
            t.join(1000);
            System.out.println("join结束了");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}

class RunnableImpl implements Runnable{

    @Override
    public void run() {
        try {
            System.out.println("开始sleep");
            Thread.sleep(1000);
            System.out.println("结束sleep");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
结果是: 开始sleep 结束sleep join结束了 =====>说明当主线程调用t.joni(1000)时,主线程等待t线程1秒钟。     但多运行几次发现,也会出现不同的结果: 开始sleep join结束了 结束sleep =====>这是因为 t 线程在进入就绪状态后,没有立刻被CPU调度分配时间片,因为CPU时间片的分配使用的是非公平策略,并不会因为先进入就绪队列就先执行,所以主线程在等待t线程1秒钟后便继续执行了,导致这样的现象出现。     如果让主线程等待1秒钟,而 t线程sleep2秒钟,那么这个现象会更加明显
@Override
public void run() {
    try {
        System.out.println("开始sleep");
        //Thread.sleep(1000);
        Thread.sleep(2000);
        System.out.println("结束sleep");
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}
结果: 开始sleep join结束了 结束sleep =====>很明显主线程只会等待1秒钟,不会理会t线程什么时候结束,1秒钟后主线程就会接着执行。     我们记着源码注释中还提了一句话,超时0意味着永远等待。也就是说主线程调用 t.join(0)或 t.join()就意味着主线程必须等待t线程执行完毕才可以执行。 join() 和 join(0) 的意义一样。在源码中我们就能知道这一点。     接着解释join源码解释下的第二点 ” main 线程调用 t.join时,必须能够拿到线程t对象的锁 “ 创造一个新线程去抢夺对象t的锁:
public class JoinTest {
    public static void main(String[] args) {
        long start=System.currentTimeMillis();
        Thread t=new Thread(new RunnableImpl());
        new MythreadTest(t).start();
        t.start();
        try {
            t.join(1000);
            System.out.println("join结束了");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("时间:"+(System.currentTimeMillis()-start));
    }
}

class RunnableImpl implements Runnable{

    @Override
    public void run() {
        try {
            System.out.println("开始sleep");
            //Thread.sleep(1000);
            Thread.sleep(2000);
            System.out.println("结束sleep");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

class MythreadTest extends Thread{

    Thread thread;

    public MythreadTest(Thread thread){
        this.thread=thread;
    }

    @Override
    public void run() {
        holdThreadLock();
    }

    public void holdThreadLock(){
        synchronized (thread){
            System.out.println("拿到对象锁");

        try {
            Thread.sleep(9000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
            System.out.println("释放对象锁");
        }
    }
}
结果: 拿到对象锁 开始sleep 结束sleep 等九秒 释放对象锁 join结束了 时间:9013 =============================== 还可能出现的结果: 开始sleep 拿到对象锁 结束sleep 等九秒 释放对象锁 join结束了 时间:9016 ==========原因同上================           在main方法中 通过new ThreadTest(t).start(); 实例化ThreadTest 线程对象, 它在holdThreadLock()方法中,通过 synchronized (thread),获取线程对象t的锁,并Sleep(9000)后释放,这就意味着,即使main方法t.join(1000),等待一秒钟,它也必须等待ThreadTest 线程释放t锁后才能进入wait方法中,它实际等待时间是9000ms~10000ms

标签:join,text,data,理解,线程,marks,nodes,type,id
From: https://www.cnblogs.com/nliu/p/17609074.html

相关文章

  • Java多线程-龟兔赛跑
    Java多线程-龟兔赛跑packagecom.alibaba;publicclassTestThread003implementsRunnable{privateStringwinner;@Overridepublicvoidrun(){for(inti=0;i<=100;i++){booleanflag=getWinner(i);if(flag){......
  • 深入理解线程与进程:概念、特点与区别,附带代码演示
    当今计算机系统中,线程(Thread)和进程(Process)是并发编程中的关键概念。它们对于提高程序的效率和性能至关重要。本篇博客将详细介绍线程和进程的概念、特点以及它们之间的区别,同时通过代码演示来加深理解。1.线程1.1概念线程是操作系统能够进行运算调度的最小单位。一个进程可以包含......
  • 多线程访问数据库报错
    在用flask实现http服务器的时候,只需要指定路由和访问方法,前端的访问就可以获取到,然后触发后端的响应函数,如果后端响应函数用公用的sqlconnection的时候,可能会导致数据库连接冲突报错,报错内容如下:AttributeError:'NoneType'objecthasnoattribute'read' 参考这篇博客的解......
  • 交换机原理(个人理解版)
    交换机原理(个人理解版)(以用户AA和用户DD为例)学习:(个人有两种理解:一种是当pc接入交换机时,交换机就会在自己的地址表上记录;一种是当pc给另一台pc发信息时,交换机收到这个数据帧再在地址表上记录,我在网上没找到明确答案,应该不重要。)AA的数据帧通过交换机的F0/1端口进入交换机1(MAC......
  • 【JointJS】ref 属性和 calc 相对计算函数
    在define函数和calc相对计算函数中提到了calc相对计算函数,默认情况下,不指定ref属性,calc以这个g标签作为基点计算值。而一个图形下面(也就是一个g标签),会有很多其他子图形,例如,<ellipse>、<text>、<rect>等。如上图所示,这是一个由define函数自定义的图形,其包含了......
  • BGP路由表中符号的理解
    解析:*:表示路由是有效路由,下一跳可达>:表示路由是BGP选出的最优路由 d:表示路由是衰减路由h:表示路由是历史路由i:表示路由是AS内部路由,来自于IBGP对等体s:处于stale状态路由,正在被删除。BGPGR过程中可能出现此标记network:BGP路由表中的网络地址nexthop:报文发送的下一跳地址MED:BGP路......
  • java多线程并发面试题总结(史上最全40道)
    1、多线程有什么用?一个可能在很多人看来很扯淡的一个问题:我会用多线程就好了,还管它有什么用?在我看来,这个回答更扯淡。所谓"知其然知其所以然","会用"只是"知其然","为什么用"才是"知其所以然",只有达到"知其然知其所以然"的程度才可以说是把一个知识点运用自如。OK,下面说说我对这个......
  • java多线程并发面试题总结(史上最全40道)
    1、多线程有什么用?一个可能在很多人看来很扯淡的一个问题:我会用多线程就好了,还管它有什么用?在我看来,这个回答更扯淡。所谓"知其然知其所以然","会用"只是"知其然","为什么用"才是"知其所以然",只有达到"知其然知其所以然"的程度才可以说是把一个知识点运用自如。OK,下面说说我对这个问......
  • 【高并发】SimpleDateFormat类到底为啥不是线程安全的?(附六种解决方案,建议收藏)
    大家好,我是冰河~~首先问下大家:你使用的SimpleDateFormat类还安全吗?为什么说SimpleDateFormat类不是线程安全的?带着问题从本文中寻求答案。提起SimpleDateFormat类,想必做过Java开发的童鞋都不会感到陌生。没错,它就是Java中提供的日期时间的转化类。这里,为什么说SimpleDateFormat类有......
  • 《深入理解Java虚拟机》读书笔记:HotSpot虚拟机对象探秘
    基于实用优先的原则,以常用的虚拟机HotSpot和常用的内存区域Java堆为例,深入探讨HotSpot虚拟机在Java堆中对象分配、布局和访问的全过程。以下是本节内容的脑图。 HotSpot虚拟机对象探秘脑图 一、对象的创建创建对象大致分为5步:1.检查类是否加载,没有加载先加载类2.分配内......