线程的合并的含义就是 将几个并行线程的线程合并为一个单线程执行,应用场景是 当一个线程必须等待另一个线程执行完毕才能执行时,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 {
@Override
public 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;
}
@Override
public void run() {
// do really something
try {
Thread.sleep(spendTime);
System.out.println(machineName + " complete data capture");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public String getResult() {
return machineName + " finish";
}
}