java多线程系类:基础篇:08之join
本章,会对Thread中join()方法进行介绍。涉及到的内容包括:
1. join()介绍
2. join()源码分析(基于JDK1.7.0_40)
3. join()示例
转载请注明出处:http://www.cnblogs.com/skywang12345/p/3479275.html
1. join()介绍
join() 定义在Thread.java中。
join() 的作用:让“主线程”等待“子线程”结束之后才能继续运行。这句话可能有点晦涩,我们还是通过例子去理解:

- // 主线程
- public class Father extends Thread {
- public void run() {
- Son s = new Son();
- s.start();
- s.join();
- ...
- }
- }
- // 子线程
- public class Son extends Thread {
- public void run() {
- ...
- }
- }

说明:
上面的有两个类Father(主线程类)和Son(子线程类)。因为Son是在Father中创建并启动的,所以,Father是主线程类,Son是子线程类。
在Father主线程中,通过new Son()新建“子线程s”。接着通过s.start()启动“子线程s”,并且调用s.join()。在调用s.join()之后,Father主线程会一直等待,直到“子线程s”运行完毕;在“子线程s”运行完毕之后,Father主线程才能接着运行。 这也就是我们所说的“join()的作用,是让主线程会等待子线程结束之后才能继续运行”!
2. join()源码分析(基于JDK1.7.0_40)

- public final void join() throws InterruptedException {
- join(0);
- }
- public final synchronized void join(long millis)
- throws InterruptedException {
- long base = System.currentTimeMillis();
- long now = 0;
- if (millis < 0) {
- throw new IllegalArgumentException("timeout value is negative");
- }
- if (millis == 0) {
- while (isAlive()) {
- wait(0);
- }
- } else {
- while (isAlive()) {
- long delay = millis - now;
- if (delay <= 0) {
- break;
- }
- wait(delay);
- now = System.currentTimeMillis() - base;
- }
- }
- }

说明:
从代码中,我们可以发现。当millis==0时,会进入while(isAlive())循环;即只要子线程是活的,主线程就不停的等待。
我们根据上面解释join()作用时的代码来理解join()的用法!
问题:
虽然s.join()被调用的地方是发生在“Father主线程”中,但是s.join()是通过“子线程s”去调用的join()。那么,join()方法中的isAlive()应该是判断“子线程s”是不是Alive状态;对应的wait(0)也应该是“让子线程s”等待才对。但如果是这样的话,s.join()的作用怎么可能是“让主线程等待,直到子线程s完成为止”呢,应该是让"子线程等待才对(因为调用子线程对象s的wait方法嘛)"?
答案:wait()的作用是让“当前线程”等待,而这里的“当前线程”是指当前在CPU上运行的线程。所以,虽然是调用子线程的wait()方法,但是它是通过“主线程”去调用的;所以,休眠的是主线程,而不是“子线程”!
3. join()示例
在理解join()的作用之后,接下来通过示例查看join()的用法。

- // JoinTest.java的源码
- public class JoinTest{
- public static void main(String[] args){
- try {
- ThreadA t1 = new ThreadA("t1"); // 新建“线程t1”
- t1.start(); // 启动“线程t1”
- t1.join(); // 将“线程t1”加入到“主线程main”中,并且“主线程main()会等待它的完成”
- System.out.printf("%s finish\n", Thread.currentThread().getName());
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- static class ThreadA extends Thread{
- public ThreadA(String name){
- super(name);
- }
- public void run(){
- System.out.printf("%s start\n", this.getName());
- // 延时操作
- for(int i=0; i <1000000; i++)
- ;
- System.out.printf("%s finish\n", this.getName());
- }
- }
- }

运行结果:
- t1 start
- t1 finish
- main finish
结果说明:
运行流程如图
(01) 在“主线程main”中通过 new ThreadA("t1") 新建“线程t1”。 接着,通过 t1.start() 启动“线程t1”,并执行t1.join()。
(02) 执行t1.join()之后,“主线程main”会进入“阻塞状态”等待t1运行结束。“子线程t1”结束之后,会唤醒“主线程main”,“主线程”重新获取cpu执行权,继续运行。
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
看完作者博客后的疑问:
上面的内容理解join不难,但是,我们看join的源代码。里面有这么一句话,也是join最主要的一句话:
- if (millis == 0) {
- while (isAlive()) {
- wait(0);
- }
- }
按照博主的分析,运行到这里的话,我们的main主线程,已经被置于等待状态了。
wait(0)的意思是不考虑实际的时间,作用就是wait();什么时候唤醒,什么时候这个线程才能继续启用。
问题是是源码里面没有交代notify()或者notifyall()什么时候会调用。
只是说我们的子线程运行结束之后,父线程就可以继续运行了。这个没有讲到核心。
java多线程系类:基础篇:08之join的更多相关文章
- Java多线程系列--“基础篇”08之 join()
概要 本章,会对Thread中join()方法进行介绍.涉及到的内容包括:1. join()介绍2. join()源码分析(基于JDK1.7.0_40)3. join()示例 转载请注明出处:http ...
- java多线程系类:基础篇:01基本概念:
这个系类的内容全部来源于http://www.cnblogs.com/skywang12345/p/3479024.html.特别在此声明!!! 本来想直接看那位作家的博客的,但还是复制过来. 多线程 ...
- java多线程系类:基础篇:06线程让步
本系类的知识点全部来源于http://www.cnblogs.com/skywang12345/p/3479243.html,我只是复制粘贴一下,特在此说明. 概要 本章,会对Thread中的线程让步 ...
- java多线程系类:基础篇:03Thread中的start()和run()的区别
这个系类的内容全部来源于http://www.cnblogs.com/skywang12345/p/3479024.html.特别在此声明!!! 概要 Thread类包含start()和run()方法 ...
- java多线程系类:JUC线程池:04之线程池原理(三)(转)
转载请注明出处:http://www.cnblogs.com/skywang12345/p/3509960.html 本章介绍线程池的生命周期.在"Java多线程系列--"基础篇& ...
- java多线程系类:JUC锁:01之框架
本章,我们介绍锁的架构:后面的章节将会对它们逐个进行分析介绍.目录如下:01. Java多线程系列--"JUC锁"01之 框架02. Java多线程系列--"JUC锁&q ...
- java多线程系类:JUC线程池:01之线程池架构
概要 前面分别介绍了"Java多线程基础"."JUC原子类"和"JUC锁".本章介绍JUC的最后一部分的内容--线程池.内容包括:线程池架构 ...
- java多线程系类:JUC线程池:03之线程池原理(二)(转)
概要 在前面一章"Java多线程系列--"JUC线程池"02之 线程池原理(一)"中介绍了线程池的数据结构,本章会通过分析线程池的源码,对线程池进行说明.内容包 ...
- java多线程系类:JUC线程池:02之线程池原理(一)
在上一章"Java多线程系列--"JUC线程池"01之 线程池架构"中,我们了解了线程池的架构.线程池的实现类是ThreadPoolExecutor类.本章,我 ...
- java多线程系类:JUC原子类:03之AtomicLongArray原子类
概要 AtomicIntegerArray, AtomicLongArray, AtomicReferenceArray这3个数组类型的原子类的原理和用法相似.本章以AtomicLongArray对数 ...
随机推荐
- android遥控器的映射
第一编写kl文件时先在盒子上输入getevent -v查看设备信息,设备信息里有vendor.product.version, 假如分别是xxxx,yyyy,zzzz,那么你的文件名就要命名为Vend ...
- Java你可能不知道的事(3)HashMap
概述 HashMap对于做Java的小伙伴来说太熟悉了.估计你们每天都在使用它.它为什么叫做HashMap?它的内部是怎么实现的呢?为什么我们使用的时候很多情况都是用String作为它的key呢?带着 ...
- 【读书笔记】iOS网络-负载
负载指的是在服务的请求响应事务中交换的数据.常见的负载格式包括XML,JSON与HTML. 进入与发出的负载数据存在很多形式与大小.比如,有些开发者会使用原生的字符串或是以分隔符分开的数据与Web S ...
- UITableView详细注释
style //普通 UITableViewStylePlain, //分组 UITableViewStyleGrouped //表格视图 UITableView * tableView = [[UI ...
- 【原】Github系列之一:一起做仿天气类应用中的实时模糊效果LiveBlur
从本文开始,我将专门开辟一个Github Code系列,开源自己写的一部分有意思而且实用的demo,共同学习.以前都发布在git OSChina上,后面有空会陆陆续续整理到Github上.OSChin ...
- android Gui系统之SurfaceFlinger(3)---SurfaceFlinger
7.SurfaceFlinger SurfaceFlinger在前面的篇幅了,多有涉及. SurfaceFlinger是GUI刷新UI的核心,所以任何关于SurfaceFlinger的改进都会对and ...
- 安装SqlServer的时候性能计数器注册表配置单元一致性失败的解决办法
http://www.2cto.com/database/201204/126772.html
- request 、response和session的区别
request: 1.request.getParameter("key")接受的是来自客户登陆端的数据,接受的是post或get方式传送的value. 2.请求的默认字符集是IS ...
- mydumper 安装报错处理
mydumper 官网:https://launchpad.net/mydumper 下载之后,安装报错: [root@localhost local]# cd mydumper-0.6.2 [roo ...
- su认证失败&文件夹里打开终端的方法&atom安装
很久没用笔记本上的ubuntu,用不顺手,比在公司调教了半年多的电脑差远了.一步一步来.先解决最不顺手的三件事 1.su认证失败. 新安装的ubuntu系统是无法切换到root账户的,得做一番修改 s ...