一、先看下Java中线程的状态
二、如何终止一个正在sleep、waiting、blocked状态的线程?
方法1:优雅方案,发中断信号,终止的决定权交给业务代码
/**
* @Project fighting-core
* @Description 如何终止一个正在sleep的线程?
* @Author lvaolin
* @Date 2021/5/25 5:26 下午
*/
public class Demo01 {
public static void main(String[] args) throws IOException, InterruptedException {
System.out.println(System.currentTimeMillis());
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
try {
System.out.println("愉快的开始");
TimeUnit.SECONDS.sleep(10);
System.out.println("愉快的结束");
} catch (InterruptedException e) {
System.out.println("我被终止了"+System.currentTimeMillis());
return;
}
System.out.println("do something");
}
});
thread.start();
TimeUnit.SECONDS.sleep(1);
thread.interrupt();
System.out.println("over");
System.in.read();
}
}
方法2 使用stop方法终止线程(过于暴力,此方法已被标记为过时、放弃,不建议使用)
/**
* @Project fighting-core
* @Description 如何终止一个正在sleep的线程?
* @Author lvaolin
* @Date 2021/5/25 5:26 下午
*/
public class Demo02 {
public static void main(String[] args) throws IOException, InterruptedException {
System.out.println(System.currentTimeMillis());
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
try {
System.out.println("愉快的开始");
TimeUnit.SECONDS.sleep(10);
System.out.println("愉快的结束");
} catch (InterruptedException e) {
System.out.println("我被终止了"+System.currentTimeMillis());
return;
}
System.out.println("do something");
}
});
thread.start();
TimeUnit.SECONDS.sleep(1);
thread.stop();
System.out.println("over");
System.in.read();
}
}
三、如何终止一个死循环中的线程?
如果你希望你的业务线程有能力被中断,具有可中断性,请再循环条件里判断 Thread.currentThread().isInterrupted() 或者 Thread.interrupted() ,它们的区别见末尾的总结部分
/**
* @Project fighting-core
* @Description 如何终止一个死循环?
* @Author lvaolin
* @Date 2021/5/25 22:07 下午
*/
public class Demo07 {
public static void main(String[] args) throws IOException, InterruptedException {
long startTime = System.currentTimeMillis();
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
while (true && !Thread.currentThread().isInterrupted()) {
System.out.println("愉快的开始");
System.out.println("愉快的结束");
}
System.out.println("我被终止了,运行了" + (System.currentTimeMillis()-startTime)+"ms");
}
});
thread.start();
TimeUnit.MILLISECONDS.sleep(1);
System.out.println("发送中断信号----");
thread.interrupt();
System.in.read();
}
}
三、如何终止一个正常执行指令的线程?
/**
* @Project fighting-core
* @Description 如何终止一个正常运行的程序?
* @Author lvaolin
* @Date 2021/5/25 22:07 下午
*/
public class Demo08 {
public static void main(String[] args) throws IOException, InterruptedException {
long startTime = System.currentTimeMillis();
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
//while (true){
//模拟正常运行的业务代码----如果希望业务具备中断能力,就需要多埋点判断中断的状态标志--
if(Thread.interrupted()){
System.out.println("我被中断了1");
return;
}
System.out.println("do something1");
if(Thread.interrupted()){
System.out.println("我被中断了2");
return;
}
System.out.println("do something2");
if(Thread.interrupted()){
System.out.println("我被中断了3");
return;
}
System.out.println("do something3");
}
//}
});
thread.start();
TimeUnit.MILLISECONDS.sleep(1);
System.out.println("发送中断信号----");
thread.interrupt();
System.in.read();
}
}
四、如何终止一个线程池中的正在执行的任务?
线程池中的任务只能使用中断信号去尝试中断已经开始的任务,无法使用stop方法暴力终止一个线程,因为没有暴露API能获取到线程引用
/**
* @Project fighting-core
* @Description 如何终止一个在线程池中运行的任务?
* @Author lvaolin
* @Date 2021/5/25 22:49 下午
*/
public class Demo10 {
static ExecutorService service = Executors.newFixedThreadPool(5);
public static void main(String[] args) throws IOException, InterruptedException {
long startTime = System.currentTimeMillis();
Future<?> future = service.submit(new Runnable() {
@Override
public void run() {
while (true&&!Thread.interrupted()){//具有中断能力的任务
//while (true){//不具有中断能力的任务,一旦开始就不能取消
System.out.println("do something");
}
System.out.println("任务被取消");
}
});
TimeUnit.MILLISECONDS.sleep(1000);
System.out.println("发送中断信号----");
//取消任务,参数true决定了即使任务已经开始运行,也会向任务发中断信号,
// 但是不能保证一定会被中断,和业务代码是否具有中断能力有关
future.cancel(true);
System.in.read();
}
}
总结
方法有两种:
1、JDK早期只提供了 Thread.stop()方法,缺点很明显,暴力终止一个线程,程序员没有任何选择的机会;
2、后来提供了优雅的方法,给了程序员选择的能力:therad.interrupt() 会向目标线程发送中断信号,对于处于sleep、wait、blocked状态的目标线程会引发InterruptedException异常,至于异常后程序该何去何从,由程序员决定。对于正常运行的程序,如果不理会这个中断信号,则不会收到任何影响;如果想让业务代码具有中断能力,则需要埋点检测中断信号的状态。
3、Thread.interrupted() 与Thread.currentThread().isInterrupted()区别
Thread.interrupted() 会同时清除中断标志,如果连续执行2次这句代码,第1句结果为true,第2句代码得到的结果会是false
//这是它的源码
public static boolean interrupted() {
return currentThread().isInterrupted(true);//参数true决定了会清除中断标志
}
Thread.currentThread().isInterrupted()不会清除中断标志,如果连续执行2次这句代码,第1句结果为true,第2句代码得到的结果也会是true
//这是它的源码
public boolean isInterrupted() {
return isInterrupted(false);//参数false决定了不会清除中断标志
}
4、关于future.cancel(true); 当参数为false时,只能取消还没有开始的任务。当参数为true时,如果任务还没开始,那么就正常取消;如果任务已经开始,那么就向线程发送中断信号,但是不一定能中断成功,这取决于业务代码是否具有中断能力。
5、中断在计算机中具有非常重要的意义,分为软中断,硬中断,可屏蔽中断,不可屏蔽中断,很有意思。