zoukankan      html  css  js  c++  java
  • Java中的线程Thread方法之---join() 分类: Android Java 2014-02-25 13:38 1393人阅读 评论(0) 收藏

    上一篇我们说到了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 plaincopy在CODE上查看代码片派生到我的代码片
    1. public final void join() throws InterruptedException {  
    2.         join(0);  
    3. }  
    我们在跟踪到join(0)方法中:

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


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

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

    版权声明:本文为博主原创文章,未经博主允许不得转载。

  • 相关阅读:
    最优比率环 SPFA+二分
    严格次小生成树
    SPFA判断负环BFS+DFS
    poj 1149 PIGS 网络流-最大流 建图理解
    9.20开始的停课日常
    Speed
    [BZOJ4827][Hnoi2017]礼物(FFT)
    中山纪念中学集训日志
    [POJ1151][HDU1542]Atlantis(线段树,扫描线)
    [BZOJ2002][洛谷P3203][Hnoi2010]Bounce 弹飞绵羊(LCT维护链长)
  • 原文地址:https://www.cnblogs.com/pjdssswe/p/4696087.html
Copyright © 2011-2022 走看看