一.线程join方法
package com.miracle.concurrency.chapter5;
public class ThreadJoin {
public static void main(String[] args) {
Thread t1 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
System.out.println(Thread.currentThread().getName() + "->" + i);
}
});
t1.start();
for (int j = 0; j < 1000; j++) {
System.out.println(Thread.currentThread().getName() + "->" + j);
}
}
}
两个线程(main 和 main线程创建的子线程)循环输出1000个数字,发现两个线程的输出内容有交叉
package com.miracle.concurrency.chapter5;
public class ThreadJoin {
public static void main(String[] args) {
Thread t1 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
System.out.println(Thread.currentThread().getName() + "->" + i);
}
});
t1.start();
try {
t1.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
for (int j = 0; j < 1000; j++) {
System.out.println(Thread.currentThread().getName() + "->" + j);
}
}
}
在t1线程调用start后,又调用了join方法,可以发现 只有等t1线程执行完毕后,main线程才开始打印
线程的join方法:如果当前线程调用join方法,那么只有当join线程结束,才会执行后续代码,也就是说会阻塞运行
同时join有几个重载方法:
- public final void join(long millis, int nanos) throws InterruptedException
最多等待millis毫秒 + nanos纳秒,然后继续执行 - public final void join(long millis) throws InterruptedException
最多等待millis毫秒,然后继续执行
二.线程interrupt方法
- public void interrupt()
在一个线程中调用另一个线程的interrupt()方法,即会向那个线程发出信号——线程中断状态已被设置。至于那个线程何去何从,由具体的代码实现决定。 - public boolean isInterrupted()
用来判断当前线程的中断状态(true or false)。 - public static boolean interrupted()
同上
package com.miracle.concurrency.chapter6;
public class ThreadInterrupt {
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(){
@Override
public void run() {
while (true) {
}
}
};
// 启动线程
t.start();
// 休眠100毫秒
Thread.sleep(100);
// 输出线程是否打断
System.out.println(t.isInterrupted());
// 向线程t发送打断信号
t.interrupt();
// 输出线程是否打断
System.out.println(t.isInterrupted());
}
}
执行上述代码发现,调用t.interrupt()之后,线程t仍然运行,需要在t内部捕获打断信号,然后进行停止操作
- interrupt打断join
package com.miracle.concurrency.chapter6;
public class ThreadInterrupt {
public static void main(String[] args){
Thread t = new Thread(){
@Override
public void run() {
while (true) {
}
}
};
t.start();
Thread main = Thread.currentThread();
Thread t2 = new Thread(){
@Override
public void run() {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 这里开启新线程,打断join main线程
main.interrupt();
System.out.println("interrupt");
}
};
t2.start();
try {
// 这里join,会阻塞的main线程
t.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
三.如何优雅的停止一个线程
1.定义开关flag,控制线程停止
package com.miracle.concurrency.chapter6;
public class ThreadCloseGraceful {
private static class Worker extends Thread{
// 开关
private volatile boolean start = true;
@Override
public void run() {
// 判断开关状态
while (this.start) {
//
}
}
public void shutdown() {
this.start = false;
}
}
public static void main(String[] args) {
Worker worker = new Worker();
worker.start();
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 关闭线程
worker.shutdown();
}
}
2.在线程内部,捕获打断信号,停止线程
package com.miracle.concurrency.chapter6;
public class ThreadCloseGraceful2 {
private static class Worker extends Thread {
@Override
public void run(){
while (true) {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
/*
调用线程的Interrupt方法,打断线程线程会捕获InterruptedException
可以通过捕获InterruptedException异常,来执行线程退出的逻辑
局限性,只能用于sleep(),join(),object.wait(),等会发出InterruptedException异常的方法
*/
// return 也可以
break;
}
}
}
}
public static void main(String[] args) {
Worker worker = new Worker();
worker.start();
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 打断线程
worker.interrupt();
}
}
- 如果线程run方法里没有执行sleep(),join(),object.wait()等会抛出InterruptedException异常的方法时,可以使用Thread的静态方法
interrupted()在线程内部判断是否打断,例如
package com.miracle.concurrency.chapter6;
public class ThreadCloseGraceful2 {
private static class Worker extends Thread {
@Override
public void run(){
while (true) {
// 判断打断信号
if (Thread.interrupted()){
break; //return
}
}
}
}
public static void main(String[] args) {
Worker worker = new Worker();
worker.start();
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 打断线程
worker.interrupt();
}
}
3.利用守护线程的特性来打断
定义工具类:ThreadService.java
package com.miracle.concurrency.chapter6;
public class ThreadService {
// 定义执行线程
private Thread executeThread;
private boolean finished = false;
public void execute(Runnable task) {
executeThread = new Thread(){
@Override
public void run() {
// 这里 利用执行线程executeThread 来创建守护线程
Thread runner = new Thread(task);
runner.setDaemon(true);
runner.start();
try {
// 这里如果不 join,那么 executeThread 结束会提前结束runner
runner.join();
finished = true;
} catch (InterruptedException e) {
}
}
};
executeThread.start();
}
// 线程关闭方法
// mills:做多等待mills毫秒
public void shutdown(long mills) {
long beginTime = System.currentTimeMillis();
while (!finished) {
// 超时
if ((System.currentTimeMillis() - beginTime) >= mills) {
System.out.println("任务超时,需要结束它");
// 打断 runner.join();
executeThread.interrupt();
break;
}
try {
executeThread.sleep(1);
} catch (InterruptedException e) {
System.out.println("执行线程被打断");
break;
}
}
finished = false;
}
}
测试类:ThreadCloseForce.java
package com.miracle.concurrency.chapter6;
public class ThreadCloseForce {
public static void main(String[] args) {
ThreadService service = new ThreadService();
long start = System.currentTimeMillis();
service.execute(() -> {
// load a very heavy resource.
while (true) {
}
});
service.shutdown(10000);
long end = System.currentTimeMillis();
System.out.println(end - start);
}
}