作用:
主线程等待子线程执行完成后结束,join()的作用是等待线程对象的销毁
1、join中断
join期间主线程被中断则不会等待子线程执行完毕,所以应该在主线程被中断时调用interrupt方法中断子线程
package com.imooc.thread_demo.join;
import lombok.Setter;
/**
* @Author: zhangjx
* @Date: 2020/9/12 16:41
* @Description:
*/
public class JoinInterrupt {
public static void main(String[] args) {
Thread thread = new Thread(new SubThread(Thread.currentThread()));
thread.start();
try {
thread.join();
} catch (InterruptedException e) {
System.out.println("主线程被中断========");;
thread.interrupt();
}
System.out.println("主线程运行完毕=========");
}
static class SubThread implements Runnable{
private Thread mainThread;
public SubThread(Thread mainThread) {
this.mainThread = mainThread;
}
@Override
public void run() {
try {
mainThread.interrupt();
Thread.sleep(5000);
} catch (InterruptedException e) {
System.out.println("子线程被中断=========");
}
System.out.println("子线程运行完毕======");
}
}
}
此时主线程被中断后子线程也会被中断。
主线程被中断========
主线程运行完毕=========
子线程被中断=========
子线程运行完毕======
2、join期间,主线程的状态
主线程运行状态为Waiting
package com.imooc.thread_demo.join;
/**
* @Author: zhangjx
* @Date: 2020/9/12 17:39
* @Description:
*/
public class JoinState {
public static void main(String[] args) {
Thread thread = new Thread(new SubThread(Thread.currentThread()));
thread.start();
try {
thread.join();
} catch (InterruptedException e) {
System.out.println("主线程被中断========");;
}
System.out.println("主线程运行完毕=========");
}
static class SubThread implements Runnable{
private Thread mainThread;
public SubThread(Thread mainThread) {
this.mainThread = mainThread;
}
@Override
public void run() {
try {
Thread.sleep(5000);
System.out.println("主线程状态:" + mainThread.getState());
} catch (InterruptedException e) {
System.out.println("子线程被中断=========");
}
System.out.println("子线程运行完毕======");
}
}
}
"C:\Program Files\Java\jdk1.8.0_171\bin\java.exe" "-javaagent:D:\idea2020\IntelliJ IDEA 2020.1.2\lib\idea_rt.jar=4155:D:\idea2020\IntelliJ IDEA 2020.1.2\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_171\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\rt.jar;C:\Users\z\Desktop\mooc\多线程\thread_demo\target\classes;E:\repository\org\springframework\boot\spring-boot-starter\2.2.2.RELEASE\spring-boot-starter-2.2.2.RELEASE.jar;E:\repository\org\springframework\boot\spring-boot\2.2.2.RELEASE\spring-boot-2.2.2.RELEASE.jar;E:\repository\org\springframework\spring-context\5.2.2.RELEASE\spring-context-5.2.2.RELEASE.jar;E:\repository\org\springframework\spring-aop\5.2.2.RELEASE\spring-aop-5.2.2.RELEASE.jar;E:\repository\org\springframework\spring-beans\5.2.2.RELEASE\spring-beans-5.2.2.RELEASE.jar;E:\repository\org\springframework\spring-expression\5.2.2.RELEASE\spring-expression-5.2.2.RELEASE.jar;E:\repository\org\springframework\boot\spring-boot-autoconfigure\2.2.2.RELEASE\spring-boot-autoconfigure-2.2.2.RELEASE.jar;E:\repository\org\springframework\boot\spring-boot-starter-logging\2.2.2.RELEASE\spring-boot-starter-logging-2.2.2.RELEASE.jar;E:\repository\ch\qos\logback\logback-classic\1.2.3\logback-classic-1.2.3.jar;E:\repository\ch\qos\logback\logback-core\1.2.3\logback-core-1.2.3.jar;E:\repository\org\apache\logging\log4j\log4j-to-slf4j\2.12.1\log4j-to-slf4j-2.12.1.jar;E:\repository\org\apache\logging\log4j\log4j-api\2.12.1\log4j-api-2.12.1.jar;E:\repository\org\slf4j\jul-to-slf4j\1.7.29\jul-to-slf4j-1.7.29.jar;E:\repository\jakarta\annotation\jakarta.annotation-api\1.3.5\jakarta.annotation-api-1.3.5.jar;E:\repository\org\springframework\spring-core\5.2.2.RELEASE\spring-core-5.2.2.RELEASE.jar;E:\repository\org\springframework\spring-jcl\5.2.2.RELEASE\spring-jcl-5.2.2.RELEASE.jar;E:\repository\org\yaml\snakeyaml\1.25\snakeyaml-1.25.jar;E:\repository\org\springframework\boot\spring-boot-devtools\2.2.2.RELEASE\spring-boot-devtools-2.2.2.RELEASE.jar;E:\repository\org\springframework\boot\spring-boot-configuration-processor\2.2.2.RELEASE\spring-boot-configuration-processor-2.2.2.RELEASE.jar;E:\repository\org\projectlombok\lombok\1.18.10\lombok-1.18.10.jar;E:\repository\org\slf4j\slf4j-api\1.7.29\slf4j-api-1.7.29.jar" com.imooc.thread_demo.join.JoinState
主线程状态:WAITING
子线程运行完毕======
主线程运行完毕=========
3、join注意点
线程执行完毕后会主动调用notify_all方法,而join实质上就是使用wait()实现的,当子线程执行完毕唤醒主线程
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等价于
synichronized(thread.wait();){
thread.wait();
}
3.1 、CountDownLatch
3.2 、CyclicBarrier