线程的合并的含义就是 将几个并行线程的线程合并为一个单线程执行,应用场景是 当一个线程必须等待另一个线程执行完毕才能执行时,Thread类提供了join方法来完成这个功能,注意,它不是静态方法。
join有3个重载的方法:
void join()当前线程等该加入该线程后面,等待该线程终止。void join(long millis)当前线程等待该线程终止的时间最长为 millis 毫秒。 如果在millis时间内,该线程没有执行完,那么当前线程进入就绪状态,重新等待cpu调度void join(long millis,int nanos)等待该线程终止的时间最长为 millis 毫秒 + nanos 纳秒。如果在millis时间内,该线程没有执行完,那么当前线程进入就绪状态,重新等待cpu调度复制代码
例子代码,如下:
/*** 在主线程中调用thread.join(); 就是将主线程加入到thread子线程后面等待执行。不过有时间限制,为1毫秒。*/public class Test1 {public static void main(String[] args) throws InterruptedException {MyThread t=new MyThread();t.start();// 将主线程加入到子线程后面,不过如果子线程在1毫秒时间内没执行完,// 则主线程便不再等待它执行完,进入就绪状态,等待cpu调度t.join(1);for(int i=0;i<30;i++){System.out.println(Thread.currentThread().getName() + "线程第" + i + "次执行!");}}}class MyThread extends Thread {@Overridepublic void run() {for (int i = 0; i < 1000; i++) {System.out.println(this.getName() + "线程第" + i + "次执行!");}}}复制代码
在JDK中join方法的源码,如下:
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方法实现是通过调用wait方法实现。当main线程调用t.join时候,main线程会获得线程对象t的锁(wait 意味着拿到该对象的锁),调用该对象的wait(等待时间),直到该对象唤醒main线程,比如退出后。这就意味着main 线程调用t.join时,必须能够拿到线程t对象的锁。
等多个线程采集数据之后再统计时间
package com.huanghe.chapter5;/*** @author River* @date 2020/8/9 7:42* @description*/public class ThreadJoin3 {public static void main(String[] args) throws InterruptedException {long startTime = System.currentTimeMillis();Thread t1 = new Thread(new CaptureRunnable("M1", 10000L));Thread t2 = new Thread(new CaptureRunnable("M2", 30000L));Thread t3 = new Thread(new CaptureRunnable("M4", 15000L));t1.start();t2.start();t3.start();// main 线程会等t1,t2,t3线程结束(t1,t2,t3的join是相对于当前线程,main线程的),t1,t2,t3会交替执行t1.join();t2.join();t3.join();long endTime = System.currentTimeMillis();System.out.printf("Save data begin timeStamp is : %s, end timestamp is:%s\n", startTime, endTime);}}class CaptureRunnable implements Runnable {private String machineName;private long spendTime;public CaptureRunnable(String machineName, Long spendTime) {this.machineName = machineName;this.spendTime = spendTime;}@Overridepublic void run() {// do really somethingtry {Thread.sleep(spendTime);System.out.println(machineName + " complete data capture");} catch (InterruptedException e) {e.printStackTrace();}}public String getResult() {return machineName + " finish";}}
