1. 线程中断
1.1 线程睡眠被打断
class ThreadSleep implements Runnable {
@Override
public void run() {
try {
System.out.println("睡眠前当前线程状态" + Thread.currentThread().isInterrupted());
while (true) {
Thread.sleep(1000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
System.out.println("当前线程状态" + Thread.currentThread().isInterrupted());
}
}
}
ThreadSleep threadSleep = new ThreadSleep();
Thread thread1 = new Thread(threadSleep);
thread1.start();
Thread.sleep(100);
thread1.interrupt();
1.2 线程运行被打断
class ThreadRun implements Runnable {
@Override
public void run() {
System.out.println("运行前线程状态" + Thread.currentThread().isInterrupted());
try {
while (true) {
Thread current = Thread.currentThread();
boolean interrupted = current.isInterrupted();
if(interrupted) {
System.out.println("当前线程状态" + interrupted);
break;
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
ThreadRun threadRun=new ThreadRun();
Thread thread1 = new Thread(threadRun);
thread1.start();
Thread.sleep(100);
thread1.interrupt();
由上可见:
对于处于睡眠状态的线程由外部打断会报出InterruptedException异常,且中断标识位为false标识为未被打断
对于正常运行的线程由外部打断不会报出异常,且中断标识为被修改成true,代表以及被打断
其次:
我们在以上两个类里面添加:
public void interruptBySelf(){
Thread.interrupted();
}
再来运行:
ThreadRun threadRun=new ThreadRun();
Thread thread1 = new Thread(threadRun);
thread1.start();
Thread.sleep(100);
// 这里改为自己打断
threadRun.interruptBySelf();
可见,由于状态位未改变一直处于运行状态
再来试试睡眠状态:
ThreadSleep threadSleep=new ThreadSleep();
Thread thread1 = new Thread(threadSleep);
thread1.start();
Thread.sleep(100);
//
threadSleep.interruptBySelf();
测试当前线程是否被中断的
* 通过这个方法可以清除线程的中断状态
在换句话说,如果这个方法被连续调用两次,则
*第二次调用将返回false(除非当前线程为false)
*在第一个呼叫清除其中断后,再次中断
在第二次通话之前)。
一个线程的中断被忽略,因为一个线程不是活的
*在中断的时候会通过这个方法反映出来
*返回false。
public static boolean interrupted() {
return currentThread().isInterrupted(true);
}
Java并发编程实战提出:
调用interrupt并不意味着停止目标线程正在执行的工作;它仅仅传递了请求中断的消息;
对中断最好的理解就是:
仅仅会发出中断请求,线程自己会在下一个方便的时刻中断;
中断是实现取消最明智的选择;
于是我们有了以下取消方法:
1.3 二阶段终止(关闭)
在一个线程 T1 中如何“优雅”终止线程 T2?
错误思路:
- 使用线程对象的 stop() 方法停止线程
stop 方法会真正杀死线程,如果这时线程锁住了共享资源,那么当它被杀死后就再也没有机会释放锁,其它线程将永远无法获取锁 - 使用 System.exit(int) 方法停止线程
目的仅是停止一个线程,但这种做法会让整个程序都停止
正确思路:
class TPTInterrupt {
private Thread thread;
public void start() {
thread = new Thread(() -> {
while (true) {
Thread current = Thread.currentThread();
if (current.isInterrupted()) {
System.out.println("准备结束");
break;
}
try {
Thread.sleep(1000);
System.out.println("运行运行....");
} catch (InterruptedException e) {
current.interrupt();
}
// 执行监控操作
}
}, "监控线程");
thread.start();
}
public void stop() {
thread.interrupt();
}
}
TPTInterrupt interrupt = new TPTInterrupt();
interrupt.start();
Thread.sleep(2000);
interrupt.stop();
2. 线程取消
2.1 Volatile取消(关闭线程)
class Cancel implements Runnable {
private volatile boolean cancelled;
@Override
public void run() {
System.out.println("任务正在执行...");
while (!cancelled) {
}
System.out.println("任务取消...");
}
public void cancel() {
this.cancelled = true;
}
}
private static void cancel() throws InterruptedException {
Cancel cancel = new Cancel();
new Thread(cancel).start();
Thread.sleep(1000);
cancel.cancel();
}
2.2 Future 取消
cancel:参数mayInterruptedIfRunning,当mayInterruptedIfRunning为true,并且当前任务正在运行,那么这个线程应该中断的,如果是false意味着如果任务没有启动,不要运行这个任务;
ExecutorService executor = Executors.newSingleThreadExecutor();
Future future = executor.submit(new ThreadRun());
Thread.sleep(100);
future.cancel(true);
注意一般要交给线程池来使用Future来取消比较好