interrupt()用法
打断正常运行的线程
interrrupt()方法可以用来打断正在运行的线程,也可以打断sleep()、wait()、join()情况下的线程,但是这些情况下被打断线程的打断标记不同。
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.TimeUnit;
@Slf4j
public class InterruptTest {
public static void main(String[] args) throws InterruptedException {
//创建一个线程
Thread t1 = new Thread(() -> {
//让线程一直死循环运行
log.debug("t1开始运行.....");
while(true){
}
},"t1");
//启动线程t1
t1.start();
//main主线程一秒后进行打断操作
TimeUnit.MILLISECONDS.sleep(1000);
log.debug("interrupt.....");
t1.interrupt();
}
}
通过控制台,可以很清晰的看到,main主线程在执行完打断操作后,t1线程并未终止运行,而是继续执行:
但是如果我们查看线程t1的打断标记会发现,t1线程的打断标记确实为true:
Boolean interrupted = Thread.currentThread().isInterrupted();这是因为main主线程执行interrupt打断操作,只是通知t1线程,我现在要打断你,但是具体的执行操作还得看t1线程,即t1线程收到main主线程的打断通知后,由t1线程自己觉得是继续运行还是被打断,从而让出cpu,这样的好处在于线程t1如果在执行某些很重要的任务,突然被其他线程强制打断可能会造成很严重的后果,这时可以让t1线程自己选择是否停止工作,也可以在停止工作之前做一些料理后事的工作 。
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.TimeUnit;
@Slf4j
public class InterruptTest {
public static void main(String[] args) throws InterruptedException {
//创建一个线程
Thread t1 = new Thread(() -> {
//让线程一直死循环运行
log.debug("t1开始运行.....");
while(true){
Boolean interrupted = Thread.currentThread().isInterrupted();
//选择被打断后的执行操作
if(interrupted){
log.debug("被打断,停止运行...");
break;
}
}
},"t1");
//启动线程t1
t1.start();
//main主线程一秒后进行打断操作
TimeUnit.MILLISECONDS.sleep(1000);
log.debug("interrupt.....");
t1.interrupt();
}
}
14:41:02.906 [t1] DEBUG InterruptTest - t1开始运行.....
14:41:03.908 [main] DEBUG InterruptTest - interrupt.....
14:41:03.908 [t1] DEBUG InterruptTest - 被打断,停止运行...
打断sleep状态的线程
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.TimeUnit;
@Slf4j
public class InterruptTest {
public static void main(String[] args) throws InterruptedException {
//创建一个线程
Thread t1 = new Thread(() -> {
//让线程一直死循环运行
log.debug("t1开始运行.....");
//t1线程休眠3秒
try {
log.debug("t1 is sleeping...");
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
},"t1");
//启动线程t1
t1.start();
//main主线程一秒后进行打断操作
TimeUnit.MILLISECONDS.sleep(1000);
log.debug("interrupt.....");
t1.interrupt();
//查看t1线程的打断标记
Boolean interrupted = t1.isInterrupted();
log.debug(interrupted.toString());
}
}
打断sleep状态的线程,会抛出InterruptedException异常,并且打断标记是false而不是true:
14:50:25.532 [t1] DEBUG InterruptTest - t1开始运行.....
14:50:25.536 [t1] DEBUG InterruptTest - t1 is sleeping...
14:50:26.533 [main] DEBUG InterruptTest - interrupt.....
14:50:26.544 [main] DEBUG InterruptTest - false
Exception in thread "t1" java.lang.RuntimeException: java.lang.InterruptedException: sleep interrupted
at InterruptTest.lambda$main$0(InterruptTest.java:17)
at java.base/java.lang.Thread.run(Thread.java:829)
Caused by: java.lang.InterruptedException: sleep interrupted
at java.base/java.lang.Thread.sleep(Native Method)
at java.base/java.lang.Thread.sleep(Thread.java:334)
at java.base/java.util.concurrent.TimeUnit.sleep(TimeUnit.java:446)
at InterruptTest.lambda$main$0(InterruptTest.java:15)
... 1 more
Process finished with exit code 0
两阶段终止模式 Two Phase Termination
在线程t1中如何优雅的终止线程t2?
- 使用stop()方法终止线程,这显然是不好的行为,因为一个线程调用了stop()方法,那么这个线程就被彻底杀死了,如果该线程正在访问一些共享资源并且加了锁,那么stop()之后该线程将再也不能释放锁,其他线程也就无法访问那些共享资源了。
- 使用System.exit()方法,这也是错误的选择,这会终止整个程序!
正确的做法是采用两阶段终止模式,具体流程如下图所示:
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.TimeUnit;
@Slf4j
public class TwoPhaseTest {
public static void main(String[] args) throws InterruptedException {
TwoPhaseTermination tpt = new TwoPhaseTermination();
tpt.start();
TimeUnit.SECONDS.sleep(4);
tpt.stop();
}
}
/**
* 监控类
*/
@Slf4j
class TwoPhaseTermination{
//监控线程
private Thread monitor;
//线程启动方法
public void start(){
monitor = new Thread(()->{
while(true){
Thread thread = Thread.currentThread();
Boolean interrupted = thread.isInterrupted();
if(interrupted){
log.debug("料理后事.....");
break;
}
try {
TimeUnit.SECONDS.sleep(1);
//每隔一秒钟执行监控任务
log.debug("监控中....");
} catch (InterruptedException e) {
e.printStackTrace();
//如果在sleep状态被打断,那么中断标记为false,需要手动置为true
thread.interrupt();
}
}});
//启动线程
monitor.start();
}
//线程终止方法
public void stop(){
//打断线程
monitor.interrupt();
}
}
15:38:11.046 [Thread-0] DEBUG TwoPhaseTermination - 监控中....
15:38:12.054 [Thread-0] DEBUG TwoPhaseTermination - 监控中....
15:38:13.060 [Thread-0] DEBUG TwoPhaseTermination - 监控中....
java.lang.InterruptedException: sleep interrupted
at java.base/java.lang.Thread.sleep(Native Method)
at java.base/java.lang.Thread.sleep(Thread.java:334)
at java.base/java.util.concurrent.TimeUnit.sleep(TimeUnit.java:446)
at TwoPhaseTermination.lambda$start$0(TwoPhaseTest.java:33)
at java.base/java.lang.Thread.run(Thread.java:829)
15:38:14.014 [Thread-0] DEBUG TwoPhaseTermination - 料理后事.....
Process finished with exit code 0
打断park()线程
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.LockSupport;
@Slf4j
public class ParkTest {
public static void main(String[] args) throws InterruptedException {
test();
}
private static void test() throws InterruptedException {
Thread t1 = new Thread(()->{
log.debug("park......");
LockSupport.park();//线程在此卡住,不继续向下执行
log.debug("unpark.......");
log.debug("打断状态:{}",Thread.currentThread().isInterrupted());
},"t1");
t1.start();
//主线程main休眠2秒
TimeUnit.SECONDS.sleep(2);
//打断t1线程
t1.interrupt();
}
}
15:51:24.581 [t1] DEBUG ParkTest - park......
15:51:26.582 [t1] DEBUG ParkTest - unpark.......
15:51:26.584 [t1] DEBUG ParkTest - 打断状态:true
标签:Java,Thread,编程,t1,线程,打断,interrupt,java,sleep From: https://www.cnblogs.com/keruanren/p/17469136.html