zoukankan      html  css  js  c++  java
  • 8.Thread的join方法

    1.Thread类的join方法表示:当前线程执行结束再执行其它线程!在Thread类中有三个重载的方法分别是:

        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;
                }
            }
        }
    
        public final synchronized void join(long millis, int nanos)
        throws InterruptedException {
    
            if (millis < 0) {
                throw new IllegalArgumentException("timeout value is negative");
            }
    
            if (nanos < 0 || nanos > 999999) {
                throw new IllegalArgumentException(
                                    "nanosecond timeout value out of range");
            }
    
            if (nanos >= 500000 || (nanos != 0 && millis == 0)) {
                millis++;
            }
    
            join(millis);
        }
    
        public final void join() throws InterruptedException {
            join(0);
        }
    

     如上就是Thread类的3个重载方法!

    大家注意一下:上面标记为红色的小红框的英文解释!以及无参的join方法,实际上调用的还是上面这个方法,如下源码所示:

    如下Demo演示:

    public class JoinDemo{  
        
        public static int a = 0;  
    
        public static void main(String[] args) throws Exception {  
            Thread t = new Thread(){
            	@Override
                public void run() {  
                    for (int k = 0; k < 5; k++) {  
                        a = a + 1;  
                    }  
                }  
              
            };  
            t.start(); 
            System.out.println(a);  
        }         
    } 
    

      请 问程序的输出结果是5吗?答案是:有可能。其实你很难遇到输出5的时候,通常情况下都不是5。当然这也和机器有严重的关系。为什么呢?我的解释是当主线程 main方法执行System.out.println(a);这条语句时,线程还没有真正开始运行,或许正在为它分配资源准备运行。因为为线程分配资源需要时间,而main方法执行完t.start()方法后继续往下执行System.out.println(a);,这个时候得到的结果是a还没有被 改变的值0 。怎样才能让输出结果为5!其实很简单,join() 方法提供了这种功能。join() 方法,它能够使调用该方法的线程在此之前执行完毕。所以代码加入了join方法之后,代码如下所示:

    public class JoinDemo{   
        public static int a = 0;  
        public static void main(String[] args) throws Exception {  
            Thread t = new Thread(){
            	@Override
                public void run() {  
                    for (int k = 0; k < 5; k++) {  
                        a = a + 1;  
                    }  
                }  
              
            };  
            t.start(); 
            t.join();//加入join方法
            System.out.println(a);  
        }         
    }
    

    为 了证明如果不使用t.join()方法,主线程main方法的System.out.println(a);语句将抢先执行,我们可以在main方法中加入一个循环,这个循环用来延长main方法执行的时间,循环次数将严重取决于机器性能。如果循环次数得当,我们也可以看到a的输出结果是5。

    public class JoinDemo{   
        public static int a = 0;  
        public static void main(String[] args) throws Exception {  
            Thread t = new Thread(){
            	@Override
                public void run() {  
                    for (int k = 0; k < 5; k++) {  
                        a = a + 1;  
                        System.out.println("a的值:"+a);
                    }  
                }  
              
            };  
            t.start(); 
            for (int i=0; i<300; i++) {                
                System.out.println(i);  
            }  
            System.out.println("静态变量的值为:"+a);  
        }         
    } 
    

     而使用了join方法之后,a的值就一直是5,但是这里需要注意的是:join方法是位于start方法之后的!

    public class JoinDemo{   
        public static int a = 0;  
        public static void main(String[] args) throws Exception {  
            Thread t = new Thread(){
            	@Override
                public void run() {  
                    for (int k = 0; k < 5; k++) {  
                        a = a + 1;  
                        System.out.println("a的值:"+a);
                    }  
                }  
              
            };  
            t.start(); 
            //join方法位于start方法之后!
            t.join();
            for (int i=0; i<300; i++) {                
                System.out.println(i);  
            }  
            System.out.println("静态变量的值为:"+a);  
        }         
    } 
    

     如下所示:

    package com.bawei.multithread;
    
    public class JoinDemo{   
        public static int a = 0;  
        public static void main(String[] args) throws Exception {  
            Thread t = new Thread(new RunnableImpl());  
           t.start();  
           try {  
               t.join(100);  
               System.out.println("joinFinish");  
           } catch (InterruptedException e) {  
               e.printStackTrace();       
           } 
        }         
    } 
    
    class RunnableImpl implements Runnable {  
        public void run() {  
            try {  
                System.out.println("Begin sleep");  
                Thread.sleep(500);  
               System.out.println("End sleep");  
            } catch (InterruptedException e) {  
                e.printStackTrace();  
            }  
      
        }  
    }  
    

     代码执行结果:

    Begin sleep
    joinFinish
    End sleep
    

     结果永远是这个,也就是说当我们为join方法指定了参数了的话,就表示main线程最多会等待这个t线程100毫秒,如果t线程100毫秒都还没执行完,那我也就不管了,我就去不等了,先去干我自己(main线程)的事了!

    但是如果我们将t线程等待的时间该为1000,我们在运行如下代码:

    package com.bawei.multithread;
    
    public class JoinDemo{   
        public static int a = 0;  
        public static void main(String[] args) throws Exception {  
            Thread t = new Thread(new RunnableImpl());  
           t.start();  
           try {  
               t.join(1000);  
               System.out.println("joinFinish");  
           } catch (InterruptedException e) {  
               e.printStackTrace();       
           } 
        }         
    } 
    
    class RunnableImpl implements Runnable {  
        public void run() {  
            try {  
                System.out.println("Begin sleep");  
                Thread.sleep(500);  
               System.out.println("End sleep");  
            } catch (InterruptedException e) {  
                e.printStackTrace();  
            }  
      
        }  
    }  
    

     此时就会看到代码的运行结果如下所示:

    Begin sleep
    End sleep
    joinFinish
    

     如下给大家演示个好玩的东西:

    public class JoinDemo{   
    
        public static void main(String[] args) throws Exception {  
          Thread.currentThread().join();
        }         
    } 
    

     虽然上面就这简简单单的几行代码,但是这个代码就是不会停止,为什么呢?

    这是因为main线程一运行,它就执行main方法中的代码:等待自己结束,但是自己有没有结束呢?没有,它也在干事情,就是:在等待自己结束,由于它永远等待不了自己结束,所以这个main线程也就永远不会退出,会一直运行下去!

     如下我们可以模拟去多台服务器上采集数据:给每台服务器开一个线程,然后通过多个线程去各个机子上采集数据,如下所示:

    //采集数据的线程Runnable【执行单元】
    class CaptureRunnable implements Runnable{
    	//机器名:标识采集的哪个机器上的数据!
    	private String machineName;
    	//花费时间
    	private long spendTime;
    	//构造函数
    	public CaptureRunnable(String machineName,long spendTime) {
    		this.machineName=machineName;
    		this.spendTime = spendTime;
    	}
    	
    	@Override
    	public void run() {
    	//do the really capture data
    		try {
    			Thread.sleep(spendTime);
    			System.out.println(machineName+" completed capture data and successfully!");
    		} catch (InterruptedException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		}
    	}
    	public String getResult(){
    		return machineName+" finish.";
    	}
    
    }
    

     上面是线程执行单元类,我们开辟几个线程,去调用这个线程执行单元,收集数据:

    public class ThreadJoin3 {
    	public static void main(String[] args) {
    		long startTimestamp = System.currentTimeMillis();
    		
    		Thread t1 =new Thread(new CaptureRunnable("M1", 10000L));
    		Thread t2 =new Thread(new CaptureRunnable("M1", 50000L));
    		Thread t3 =new Thread(new CaptureRunnable("M1", 30000L));
    		t1.start();
    		t2.start();
    		t3.start();
    		
    		long endTimestamp = System.currentTimeMillis();
    		System.out.printf("save data begin timestamp: %s, end timestamp is: %s",startTimestamp,endTimestamp);
    	}
    }
    

     如果是直接这样写的话,大家运行一下就可以看到:线程1【t1】,线程2【t2】,线程3【t3】实际上还没结束呢,但是save data begin timestamp: 1501562292242, end timestamp is ...这句话就已经打印出来了,而且这句话还是提示人家数据采集已经结束了,这样貌似真的不好哎!那怎么办呢?各个线程结束的时间也不是统一的,那这到底怎么解决呢?通过线程对象.join()方法这样就可以将这个解决了,在所有线程采集完毕数据之后,我们再保存数据,保存的是最后那个线程采集数据结束的时间!代码如下所示:

    package com.bawei.multithread;
    
    public class ThreadJoin3 {
    	public static void main(String[] args) {
    		try {
    			long startTimestamp = System.currentTimeMillis();
    			
    			Thread t1 =new Thread(new CaptureRunnable("M1", 10000L));
    			Thread t2 =new Thread(new CaptureRunnable("M1", 50000L));
    			Thread t3 =new Thread(new CaptureRunnable("M1", 30000L));
    			t1.start();
    			t2.start();
    			t3.start();
    			
    			t1.join();
    			t2.join();
    			t3.join();
    
    			long endTimestamp = System.currentTimeMillis();
    			System.out.printf("save data begin timestamp: %s, end timestamp is: %s",startTimestamp,endTimestamp);
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}
    	}
    }
    
  • 相关阅读:
    struts2 DMI
    MFC添加背景图片
    c++ 副本构造器
    climits
    Qt中的qreal
    Http概述(一)
    重构学习-重构原则
    QDir的mkdir和mkpath区别
    Qt学习笔记网络(一)
    Qt5 新特性
  • 原文地址:https://www.cnblogs.com/python-machine/p/7267783.html
Copyright © 2011-2022 走看看