java多线程系列 join java多线程:

 


java多线程与单线程相比,最大的优点是在多任务的情况下多线程比单线耗时短,可以并发进行

有时候对于单核计算机,我们也觉得很多任务是并发进行的,主要是因为我们的单核cpu对时间进行分片,对

每个任务都分配了时间片。比如给qq分配3ms给腾讯视频分了3ms等等,虽然我们看任务是并行的,实则是

分时运行的。而多核cpu则可以真正并发,这就是多核cpu执行的优势。

下面有一个简单的程序是对java单线程多线程的比较

public class ConcurrencyTest {
private static final long count = 1000000001;
	
	public static void main(String args[]) throws InterruptedException
	{
		concurrency();
		seria();
	}
	//多线程情况下
	private static void  concurrency() throws InterruptedException
	{	//获取当前系统时间
		long start = System.currentTimeMillis();
		Thread thread = new Thread(new Runnable()
		{
			@Override
			public void run() 
			{
				long a = 0;
				for(int i = 0;i < count;i++)
				{
					a+=5;
				}
			}	
		});
		thread.start();
		long b = 0;
		for(int i = 0;i <count;i++)
		{
			b+=5;
		}
		thread.join();//简单理解为等待线程结束,如果线程没有结束的话时间统计不准确
		long time = System.currentTimeMillis() - start;
		System.out.println("concurrency: " +time +" b: "+ time);
	}
	//顺序执行的情况
	private static void seria()
	{
		long start = System.currentTimeMillis();
				long a = 0;
				for(int i = 0;i < count;i++)
				{
					a+=5;
				}
		long b = 0;
		for(int i = 0;i <count;i++)
		{
			b+=5;
		}
		long time = System.currentTimeMillis() - start;
		System.out.println("concurrency: " +time +" b: "+ time);
	}
}
package java_Join;

public class ConcurrencyTest {
private static final long count = 1000000001;	
	public static void main(String args[]) throws InterruptedException
	{
		concurrency();
		seria();
	}
	//多线程情况下
	private static void  concurrency() throws InterruptedException
	{	//获取当前系统时间
		long start = System.currentTimeMillis();
		Thread thread = new Thread(new Runnable()
		{
			@Override
			public void run() 
			{
				long a = 0;
				for(int i = 0;i < count;i++)
				{
					a+=5;
				}
			}	
		});
		thread.start();
		long b = 0;
		for(int i = 0;i <count;i++)
		{
			b+=5;
		}
		thread.join();//简单理解为等待线程结束,如果线程没有结束的话时间统计不准确
		long time = System.currentTimeMillis() - start;
		System.out.println("concurrency: " +time +" b: "+ time);
	}
	//顺序执行的情况
	private static void seria()
	{
		long start = System.currentTimeMillis();
				long a = 0;
				for(int i = 0;i < count;i++)
				{
					a+=5;
				}
		long b = 0;
		for(int i = 0;i <count;i++)
		{
			b+=5;
		}
		long time = System.currentTimeMillis() - start;
		System.out.println("concurrency: " +time +" b: "+ time);
	}
}


其中执行的任务越大,效果越明显。

其中对join的理解其中有参照

个人简单理解是将该线程加入到主线程,主线程要等待其结束,如果该线程没有结束主线程不能结束

比如,你想喝茶,你要烧水,洗茶具,泡茶,喝茶。烧水与洗茶具没什么关联,你可以分开进行,但

是你喝茶的话必须得每件事都完成,所以烧水这种费时的动作就交由一个线程去做,等洗好茶具等烧

水线程完成,就可以泡茶喝茶了。

一、使用方式。

join是Thread类的一个方法,启动线程后直接调用例如

Thread t = new AThread(); t.start(); t.join();

二、为什么要用join()方法 

在很多情况下,主线程生成并起动了子线程,如果子线程里要进行大量的耗时的运算,主线程往往将于子线程之前结束,但是如果主线程处理完其他的事务后,需要用到子线程的处理结果,也就是主线程需要等待子线程执行完成之后再结束,这个时候就要用到join()方法了。

三、join方法的作用

join
public final void join() throws InterruptedException Waits for this thread to die. 
Throws: InterruptedException  - if any thread has interrupted the current thread. 
The interrupted status of the current thread is cleared when this exception is thrown.

即join()的作用是:“等待该线程终止”,这里需要理解的就是该线程是指的主线程等待子线程的终止。也就是在子线程调用了join()方法后面的代码,只有等到子线程结束了才能执行。

四、从源码看join()方法

join()的JDK源码

 /**
     * Waits for this thread to die.
     * <p> An invocation of this method behaves in exactly the same
     * way as the invocation
     *
     * <blockquote>
     * {@linkplain #join(long) join}{@code (0)}
     * </blockquote>
     * @throws  InterruptedException
     *          if any thread has interrupted the current thread. The
     *          <i>interrupted status</i> of the current thread is
     *          cleared when this exception is thrown.
     */
    public final void join() throws InterruptedException {
        join(0);
    }
 /**
     * Waits at most {@code millis} milliseconds for this thread to
     * die. A timeout of {@code 0} means to wait forever.
     *
     * <p> This implementation uses a loop of {@code this.wait} calls
     * conditioned on {@code this.isAlive}. As a thread terminates the
     * {@code this.notifyAll} method is invoked. It is recommended that
     * applications not use {@code wait}, {@code notify}, or
     * {@code notifyAll} on {@code Thread} instances.
     *
     * @param  millis
     *         the time to wait in milliseconds
     *
     * @throws  IllegalArgumentException
     *          if the value of {@code millis} is negative
     *
     * @throws  InterruptedException
     *          if any thread has interrupted the current thread. The
     *          <i>interrupted status</i> of the current thread is
     *          cleared when this exception is thrown.
     */
    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()的用法: 

主要包含三个类

1.TestDemo 类

1.AThread 类 

2.BThread类 

TestDemo 类是主类main线程,主类里面加入了AThread 类的线程,AThread 类又加入了BThread类 

  1. class AThread extends Thread {
        BThread bt;
        public AThread(BThread bt) {
            super("[AThread] Thread");
            this.bt = bt;
        }
        public void run() {
            String threadName = Thread.currentThread().getName();
            System.out.println(threadName + " start.");
            try {
    // 这里加入了bt线程 
                bt.join();
                System.out.println(threadName + " end.");
            } catch (Exception e) {
                System.out.println("Exception from " + threadName + ".run");
            }
        }
    }
    
    
    class BThread extends Thread {
        public BThread() {
            super("[BThread] Thread");
        };
        public void run() {
            String threadName = Thread.currentThread().getName();
            System.out.println(threadName + " start.");
            try {
                for (int i = 0; i < 5; i++) {
                    System.out.println(threadName + " loop at " + i);
                    Thread.sleep(1000);
                }
                System.out.println(threadName + " end.");
            } catch (Exception e) {
                System.out.println("Exception from " + threadName + ".run");
            }
        }
    }
    public class TestDemo {
        public static void main(String[] args) {
            String threadName = Thread.currentThread().getName();
            System.out.println(threadName + " start."+"时间 :"+System.currentTimeMillis());
            BThread bt = new BThread();
            AThread at = new AThread(bt);
            try {
                bt.start();
                Thread.sleep(2000);
                at.start();
                at.join();
            } catch (Exception e) {
                System.out.println("Exception from main");
            }
            System.out.println(threadName + " end!"+"时间 :"+System.currentTimeMillis());
        }
    }

    最后结果为
    
    

可以看得到进程运行变化。

main start.时间 :1497456321225
//主线程起动,因为调用了at.join(),要等到at结束了,此线程才能向下执行
主线程睡眠2000ms
[BThread] Thread start.时间 :1497456321226[BThread] Thread loop at 0时间 :1497456321226
//睡眠1000ms
[BThread] Thread loop at 1时间 :1497456322230
//睡眠1000ms
[BThread] Thread loop at 2时间 :1497456323231
[AThread] Thread start.
//A程起动,因为调用了bt.join(),要等到bt结束了,此线程才能向下执行
[BThread] Thread loop at 3时间 :1497456324236
[BThread] Thread loop at 4时间 :1497456325241
[BThread] Thread end.时间 :1497456326245
[AThread] Thread end.
// 线程AThread在bt.join();阻塞处开始启动,向下继续执行的结果
main end!
//线程AThread结束,此线程在at.join();阻塞处开始启动,向下继续执行的结果。

修改主方法类:

public class TestDemo {
    public static void main(String[] args) {
        String threadName = Thread.currentThread().getName();
        System.out.println(threadName + " start."+"时间 :"+System.currentTimeMillis());
        BThread bt = new BThread();
        AThread at = new AThread(bt);
        try {
            bt.start();
            Thread.sleep(2000);
            at.start();
            //at.join(); //在此处注释掉对join()的调用
        } catch (Exception e) {
            System.out.println("Exception from main");
        }
        System.out.println(threadName + " end!"+"时间 :"+System.currentTimeMillis());
    }
}
结果为
main start.时间 :1497457025126
 // 主线程起动,因为Thread.sleep(2000),主线程没有马上结束;
[BThread] Thread start.时间 :1497457025128
//线程BThread起动
[BThread] Thread loop at 0时间 :1497457025128
[BThread] Thread loop at 1时间 :1497457026128
main end!时间 :1497457027128
//2000ms后主线程结束,留下AThread,与BThread
[AThread] Thread start.
//2000ms线程at启动,因为调用了bt.join(),等到bt结束了,此线程才向下执行。
[BThread] Thread loop at 2时间 :1497457027128
[BThread] Thread loop at 3时间 :1497457028130
[BThread] Thread loop at 4时间 :1497457029131
[BThread] Thread end.时间 :1497457030137
//线程BThread结束了,线程AThread在bt.join();阻塞处开始启动,向下继续执行的结果
[AThread] Thread end.



参考文章:http://www.open-open.com/lib/view/open1371741636171.html

             
             




















  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值