java 线程方法join的简单总结
虽然关于讨论线程join方法的博客已经很多了,不过个人感觉挺多都讨论得不够全面,所以我觉得有必要对其进行一个全面的总结。
一、作用
Thread类中的join方法的主要作用就是同步,它可以使得线程之间的并行执行变为串行执行。具体看代码:
public class JoinTest {
public static void main(String [] args) throws InterruptedException {
ThreadJoinTest t1 = new ThreadJoinTest("小明");
ThreadJoinTest t2 = new ThreadJoinTest("小东");
t1.start();
/**join的意思是使得放弃当前线程的执行,并返回对应的线程,例如下面代码的意思就是:
程序在main线程中调用t1线程的join方法,则main线程放弃cpu控制权,并返回t1线程继续执行直到线程t1执行完毕
所以结果是t1线程执行完后,才到主线程执行,相当于在main线程中同步t1线程,t1执行完了,main线程才有执行的机会
*/
t1.join();
t2.start();
}
}
class ThreadJoinTest extends Thread{
public ThreadJoinTest(String name){
super(name);
}
@Override
public void run(){
for(int i=0;i<1000;i++){
System.out.println(this.getName() + ":" + i);
}
}
}
上面程序结果是先打印完小明线程,在打印小东线程;
上面注释也大概说明了join方法的作用:在A线程中调用了B线程的join()方法时,表示只有当B线程执行完毕时,A线程才能继续执行。注意,这里调用的join方法是没有传参的,join方法其实也可以传递一个参数给它的,具体看下面的简单例子:
public class JoinTest {
public static void main(String [] args) throws InterruptedException {
ThreadJoinTest t1 = new ThreadJoinTest("小明");
ThreadJoinTest t2 = new ThreadJoinTest("小东");
t1.start();
/**join方法可以传递参数,join(10)表示main线程会等待t1线程10毫秒,10毫秒过去后,
* main线程和t1线程之间执行顺序由串行执行变为普通的并行执行
*/
t1.join(10);
t2.start();
}
}
class ThreadJoinTest extends Thread{
public ThreadJoinTest(String name){
super(name);
}
@Override
public void run(){
for(int i=0;i<1000;i++){
System.out.println(this.getName() + ":" + i);
}
}
}
上面代码结果是:程序执行前面10毫秒内打印的都是小明线程,10毫秒后,小明和小东程序交替打印。
所以,join方法中如果传入参数,则表示这样的意思:如果A线程中掉用B线程的join(10),则表示A线程会等待B线程执行10毫秒,10毫秒过后,A、B线程并行执行。需要注意的是,jdk规定,join(0)的意思不是A线程等待B线程0秒,而是A线程等待B线程无限时间,直到B线程执行完毕,即join(0)等价于join()。
二、join与start调用顺序问题
上面的讨论大概知道了join的作用了,那么,入股 join在start前调用,会出现什么后果呢?先看下面的测试结果
public class JoinTest {
public static void main(String [] args) throws InterruptedException {
ThreadJoinTest t1 = new ThreadJoinTest("小明");
ThreadJoinTest t2 = new ThreadJoinTest("小东");
/**join方法可以在start方法前调用时,并不能起到同步的作用
*/
t1.join();
t1.start();
//Thread.yield();
t2.start();
}
}
class ThreadJoinTest extends Thread{
public ThreadJoinTest(String name){
super(name);
}
@Override
public void run(){
for(int i=0;i<1000;i++){
System.out.println(this.getName() + ":" + i);
}
}
}
上面代码执行结果是:小明和小东线程交替打印。
所以得到以下结论:join方法必须在线程start方法调用之后调用才有意义。这个也很容易理解:如果一个线程都没有start,那它也就无法同步了。
三、join方法实现原理
有了上面的例子,我们大概知道join方法的作用了,那么,join方法实现的原理是什么呢?
其实,join方法是通过调用线程的wait方法来达到同步的目的的。例如,A线程中调用了B线程的join方法,则相当于A线程调用了B线程的wait方法,在调用了B线程的wait方法后,A线程就会进入阻塞状态,具体看下面的源码:
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;
}
}
}
从源码中可以看到:join方法的原理就是调用相应线程的wait方法进行等待操作的,例如A线程中调用了B线程的join方法,则相当于在A线程中调用了B线程的wait方法,当B线程执行完(或者到达等待时间),B线程会自动调用自身的notifyAll方法唤醒A线程,从而达到同步的目的。
java 线程方法join的简单总结的更多相关文章
- Java并发编程:Java Thread方法join的简单总结
虽然关于讨论线程join方法的博客已经很多了,不过个人感觉挺多都讨论得不够全面,所以我觉得有必要对其进行一个全面的总结. 一.作用 Thread类中的join方法的主要作用就是同步,它可以使得线程之间 ...
- java线程方法join的总结
虽然关于讨论线程join方法的博客已经很多了,不过个人感觉挺多都讨论得不够全面,所以我觉得有必要对其进行一个全面的总结. 一.作用 Thread类中的join方法的主要作用就是同步,它可以使得线程之间 ...
- java 线程方法 ---- join()
class MyThread2 implements Runnable{ @Override public void run() { for (int i = 0; i < 5; i++){ S ...
- java 线程协作 join()
在实际开发中我们往往会遇到这样的情况一个线程的执行需要依赖另一个线程执行后的结果.即主线程生成并起动了子线程,如果子线程里要进行大量的耗时的运算,主线程往往将于子线程之前结束,但是如果主线程处理完其他 ...
- Java线程--interrupt join yield setDaemon常用方法的使用
概念: 操作系统可以有多个进程,一个线程可以有一个或多个线程.进程与进程之间不共享内存,都在各自的空间中运行.而线程不仅可以共享内存,还可以用有一个自己的内存空间,叫做线程栈. 线程又称轻量级进程.J ...
- 【细说Java】方法重载的简单介绍
1. 什么是重载 方法名称相同,但它们的参数类型或个数不同,这样,方法在被调用时编译器就可以根据参数的类型与个数的不同加以区分,这就是方法的重载. 既然可以通过参数类型或参数个数来作为重载条件,那返回 ...
- Java 线程方法
线程标识相关 方法 描述 public Thread(Runnable target, String name) 带参数的构造方法, 第二个参数是线程名称 public static Thread ...
- java 线程 wait join sleep yield notify notifyall synchronized
韩梦飞沙 韩亚飞 313134555@qq.com yue31313 han_meng_fei_sha 休息方法 : 在指定时间内 让该线程 暂停, 不会释放 锁标志. 等待方法: 让 该 线 ...
- java 数组排序方法整理,简单易懂,
1.快速排序:首先是最简单的Array.sort,直接进行排序: public static void main(String[] args) { int[] arr = {4,3,5,1,7,9,3 ...
随机推荐
- TabBar自定义方式(一)
1.思路:创建一个继承UIView的TabBar类,并将需要的item添加到TabBar上面去,并用代理来处理相应的时间 [self.view bringSubviewToFront:self.one ...
- Android中实现定时器的四种方式
第一种方式利用Timer和TimerTask 1.继承关系 java.util.Timer 基本方法 schedule 例如: timer.schedule(task, delay,period); ...
- 从零开始用 Flask 搭建一个网站(二)
从零开始用 Flask 搭建一个网站(一) 介绍了如何搭建 Python 环境,以及 Flask 应用基本项目结构.我们要搭建的网站是管理第三方集成的控制台,类似于 Slack. 本篇主要讲解数据如何 ...
- start with connect by prior 递归查询用法,很实用
当开发过程需要查询上下级机构类似的树形机构,还有就是查询当前等级下的所有所属节点 这个子句主要是用于B树结构类型的数据递归查询,给出B树结构类型中的任意一个结点,遍历其最终父结点或者子结点. 先看原始 ...
- 利刃 MVVMLight 6:命令基础
在MVVM Light框架中,事件是WPF应用程序中UI与后台代码进行交互的最主要方式,与传统方式不同,mvvm中主要通过绑定到命令来进行事件的处理, 因此要了解mvvm中处理事件的方式,就必须先熟悉 ...
- Java Script 字符串操作
JS中常用几种字符串操作: big() small() bold() fontcolor() fontsize() italics() strike() link() charAt() charCod ...
- java多线程基本概述(二)——Thread的一些方法
在Thread类中有很多方法值得我们关注一下.下面选取几个进行范例: 1.1.isAlive()方法 java api 描述如下: public final boolean isAlive() Tes ...
- 【shell编程基础3】shell编程的组合应用之二:管道及其命令
预备知识: 管道:它是一个单向的,可以把前一个的数据输出导向到下一个命令的工具,这样可以实现多个命令组合处理一套数据. 它的符号是 "|" 管道只能处理经过前面一个命令传过 ...
- Linux 系统管理04--账号管理
Linux系统管理04--账号管理 一.用户账号管理 1.用户账号概述 (1)用户账号的常见分类: 1>超级用户:root uid=0 gid=0 权限最大. 2>普通用户:uid> ...
- xmlplus 组件设计系列之六 - 下拉刷新
"下拉刷新"由著名设计师 Loren Brichter 设计,并应用于 Twitter 第三方应用 Tweetie 中.2010年4月,Twitter 收购 Tweetie 开发商 ...