上一篇我们说到了Thread中的stop方法,这一篇我们再来看一下方法join的使用,那么方法Join是干啥用的? 简单回答,同步,如何同步? 怎么实现的? 下面将逐个回答。

join方法从字面上的意思就是加入到一个线程中,这样就可以很好的进行线程之间的交互运行了,不多说先来看一下代码:

package com.threadjoin.demo;

public class ThreadJoin {

	public static int a = 0;

	public static void main(String[] args){
Thread thread = new Thread(new Runnable(){
@Override
public void run(){
for(int i=0;i<5;i++)
a++;
}
});
thread.start();
/*try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}*/
System.out.println(a); } }

运行代码,貌似永远都看不到a的值是5,而每次都是0,原因很简单的,因为在thread中的run方法中进行a的增值操作,这些可能都是需要时间的,但是此时main线程中的System.out.println方法已经执行了,所以很难看到a的值是5,为了看到a的值是5,我的一个思路就是等thread运行结束之后,我们采取执行System.out.println就可以了,这时候join方法的作用就显现出来的,我们把上面的注释代码删除注释,然后运行,不管运行多少次,输出的结果都是5,从这个例子中我们就可以看到join方法的作用,它能够调节各个线程之间的运行顺序,从而可以实现同步。为了更好的了解join的运行原理我们只有看他的源码了:

[java] view
plain
copy

  1. public final void join() throws InterruptedException {
  2. join(0);
  3. }

我们在跟踪到join(0)方法中:

[java] view
plain
copy

  1. //方法是个同步的,而且会抛出InterruptedException异常
  2. public final synchronized void join(long millis) throws InterruptedException {
  3. long base = System.currentTimeMillis();
  4. long now = 0;
  5. if (millis < 0) {
  6. throw new IllegalArgumentException("timeout value is negative");
  7. }
  8. //我们可以看到这里使用了while循环做判断的,然后调用wait方法的,所以说join方法的执行是完全通过wait方法实现的
  9. //等待时间为0的时候,就是无限等待,直到线程死亡了(即线程执行完了)
  10. if (millis == 0) {
  11. //如果当前线程还存活的话,就等待
  12. while (isAlive()) {
  13. //调用该线程的join方法的线程拿到锁之后进行等待,直到线程执行结束(这个例子就是main线程)
  14. wait(0);
  15. }
  16. } else {
  17. //如果是等待的特定时间的话
  18. while (isAlive()) {
  19. long delay = millis - now;
  20. if (delay <= 0) {
  21. break;
  22. }
  23. wait(delay);
  24. now = System.currentTimeMillis() - base;
  25. }
  26. }
  27. }

从代码中我们可以看到join方法是个同步的,这个我们后面会做个例子,然后进入到方法中我们可以看到,有两种情况,一种是等待时间是0的,其实就等同无线等待,直到线程执行结束了,还有一种就是要等待的是一定的时间,原理都是一样的,

看完源码之后我们在看一一个例子:

[java] view
plain
copy

  1. package com.threadjoin.demo;
  2. /**
  3. *
  4. 其实Join方法实现是通过wait(小提示:Object 提供的方法)。
  5. 当main线程调用t.join时候,main线程会获得线程对象t的锁(wait意味着拿到该对象的锁),
  6. 调用该对象的wait(等待时间),直到该对象唤醒main线程,比如退出后。
  7. 这就意味着main 线程调用t.join时,
  8. 必须能够拿到线程t对象的锁,如果拿不到它是无法wait的,刚开的例子t.join(1000)不是说明了main线程等待1秒,
  9. 如果在它等待之前,其他线程获取了t对象的锁,它等待时间可不就是1秒了
  10. * @author weijiang204321
  11. *
  12. */
  13. public class ThreadJoinTest {
  14. public static void main(String[] args) {
  15. Thread t = new Thread(new RunnableImpl());
  16. new ThreadTest(t).start();
  17. t.start();
  18. try {
  19. t.join(1000);
  20. System.out.println("joinFinish");
  21. } catch (InterruptedException e) {
  22. e.printStackTrace();
  23. }
  24. }
  25. }
  26. class RunnableImpl implements Runnable {
  27. @Override
  28. public void run() {
  29. try {
  30. System.out.println("Begin sleep");
  31. Thread.sleep(1000);
  32. System.out.println("End sleep");
  33. } catch (InterruptedException e) {
  34. e.printStackTrace();
  35. }
  36. }
  37. }
  38. class ThreadTest extends Thread {
  39. Thread thread;
  40. public ThreadTest(Thread thread) {
  41. this.thread = thread;
  42. }
  43. @Override
  44. public void run() {
  45. holdThreadLock();
  46. }
  47. public void holdThreadLock() {
  48. //用当前的线程当做lock
  49. synchronized (thread) {
  50. System.out.println("getObjectLock");
  51. try {
  52. Thread.sleep(9*1000);
  53. } catch (InterruptedException ex) {
  54. ex.printStackTrace();
  55. }
  56. System.out.println("ReleaseObjectLock");
  57. }
  58. }
  59. }

在main方法中 通过new  ThreadTest(t).start()实例化 ThreadTest 线程对象,
它 通过 synchronized  (thread) ,获取线程对象t的锁,并sleep(9*1000)后释放,因为我们上面看到了join方法是个同步的,而且同步锁是当前的线程对象,因为ThreadTest先运行的,首先拿到了线程t对象的锁,所以join方法还没有拿到锁,所以要等待。这就意味着,即使main方法t.join(1000)等待一秒钟,它必须等待ThreadTest 线程释放t锁后才能进入wait方法中,它实际等待时间是9000+1000ms=10s。

Java中的线程Thread方法之---join()的更多相关文章

  1. Java中的线程Thread方法之---interrupt()

    前几篇都介绍了Thread中的几个方法,相信大家都发现一个相似点,那就是sleep,join,wait这样的阻塞方法都必须捕获一个InterruptedException异常,顾名思义就是一个线程中断 ...

  2. Java中的线程Thread方法之---suspend()和resume()

    前篇说到了Thread中的join方法,这一篇我们就来介绍一下suspend()和resume()方法,从字面意义上可以了解到这两个方法是一对的,suspend()方法就是将一个线程挂起(暂停),re ...

  3. Java中的线程Thread方法之---stop()

    搞过Java线程的人都知道,stop这个方法是臭名昭著了,早就被弃用了,但是现在任然有很多钟情与他的人,永远都放不下他,因为从他的字面意思上我们可以知道他貌似可以停止一个线程,这个需求是每个搞线程开发 ...

  4. Java中的线程Thread总结

    首先来看一张图,下面这张图很清晰的说明了线程的状态与Thread中的各个方法之间的关系,很经典的! 在Java中创建线程有两种方法:使用Thread类和使用Runnable接口. 要注意的是Threa ...

  5. Java中实现线程的方法

    Java中有几种方法可以实现一个线程?用什么关键字修饰同步方法?stop()和suspend()方法为何不推荐使用? 第一种:继承Thread类 new Thread(){}.start();这表示调 ...

  6. Java 中的线程 thread

    一.问:线程有哪些状态? new, runnable, running, waiting, dead 线程状态间的流转 二.问:线程实现方式? 实现 Runnable 接口,然后new Thread, ...

  7. 【Java中的线程】java.lang.Thread 类分析

    进程和线程 联想一下现实生活中的例子--烧开水,烧开水时是不是不需要在旁边守着,交给热水机完成,烧开水这段时间可以去干一点其他的事情,例如将衣服丢到洗衣机中洗衣服.这样开水烧完,衣服洗的也差不多了.这 ...

  8. JAVA中创建线程的三种方法及比较

    JAVA中创建线程的方式有三种,各有优缺点,具体如下: 一.继承Thread类来创建线程 1.创建一个任务类,继承Thread线程类,因为Thread类已经实现了Runnable接口,然后重写run( ...

  9. JAVA中创建线程池的五种方法及比较

    之前写过JAVA中创建线程的三种方法及比较.这次来说说线程池. JAVA中创建线程池主要有两类方法,一类是通过Executors工厂类提供的方法,该类提供了4种不同的线程池可供使用.另一类是通过Thr ...

随机推荐

  1. vue 2.1.3 实时显示当前时间,每秒更新

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  2. jedate(日期插件)

    首先要引入JQuery,然后引入jedate.css和jedate.js(注:需要把下载好的jedate文件夹整个的放在项目中,不然图标无法显示) 没有把整个文件夹放进去的效果            ...

  3. Python装饰器使用技巧

    装饰器 装饰器是程序开发中经常会用到的一个功能,用好了装饰器,开发效率如虎添翼,所以这也是Python面试中必问的问题,但对于好多初次接触这个知识的人来讲,这个功能有点绕,自学时直接绕过去了,然后面试 ...

  4. 转载 如何理解API,API 是如何工作的

    本文转载于https://blog.csdn.net/cumtdeyurenjie/article/details/80211896 感谢作者 仁杰兄 大家可能最近经常听到 API 这个概念,那什么是 ...

  5. vue 项目 多选 问题

    近期 vue 项目用到多选功能,引用的elementUI的级联多选 Cascader,但是没有效果. 后来发现是elementUI版本问题,我们项目用的是2.7.2版本,版本太低. 后来 卸载了 重新 ...

  6. jquery基础知识实例(一)

    轮滑 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.o ...

  7. centos修改、保存文件的详细步骤

    [一]修改文件 如果是使用普通用户登录的,需要先切换到管理员用户,打开终端,输入:su,接着按提示输入密码即可:然后使用命令进入需要修改文件的所在目录,常用的几个命令如下: ① cd + 目录名 ② ...

  8. Ext OOP基础

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  9. 学 Win32 汇编[22] - 逻辑运算指令: AND、OR、XOR、NOT、TEST

    AND: 逻辑与 ;该指令会置 CF=OF=; 其结果影响 SF.ZF.PF ;指令格式: AND r/m, r/m/i ; Test22_1.asm - 使用 AND 运算将一个数的第二.四位清零 ...

  10. (转)OpenFire源码学习之九:OF的缓存机制

    转:http://blog.csdn.net/huwenfeng_2011/article/details/43415023 关于缓存,openfire存储到了本地JVM中.本人认为这样并不是很好.以 ...