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类 


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.

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.