一个线程,是无法简单的中断的,我们只能通过告诫的方法,但是无法强制中断,仅仅是将线程对象的中断标识设为true。
一.3大API
- ①. void interrupt( )实例方法
- interrupt( )仅仅是设置线程的中断状态未true,不会停止线程
- 如果这个线程因为wait()、join()、sleep()方法在用的过程中被打断(interupt),会抛出Interrupte dException)
②. boolean isInterrupted( )实例方法
判断当前线程是否被中断(通过检查中断标识位) 实例方法
③. static boolean interrupted( )静态方法
判断线程是否被中断,并清除当前中断状态,这个方法做了两件事
(返回当前线程的中断状态 | 将当前线程的中断状态设为false)
二.三种中断标识停止线程的方式
- 通过一个volatile变量实现
- 通过AtomicBoolean
- 通过Thread类自带的中断API方法实现
-
public class InterruptDemo{ static volatile boolean isStop = false; static AtomicBoolean atomicBoolean = new AtomicBoolean(false); public static void m3(){ Thread t1 = new Thread(() -> { while (true) { if (Thread.currentThread().isInterrupted()) { System.out.println("-----isInterrupted() = true,程序结束。"); break; } System.out.println("------hello Interrupt"); } }, "t1"); t1.start(); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } new Thread(() -> { t1.interrupt();//修改t1线程的中断标志位为true },"t2").start(); } /** * 通过AtomicBoolean */ public static void m2(){ new Thread(() -> { while(true) { if(atomicBoolean.get()) { System.out.println("-----atomicBoolean.get() = true,程序结束。"); break; } System.out.println("------hello atomicBoolean"); } },"t1").start(); //暂停几秒钟线程 try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } new Thread(() -> { atomicBoolean.set(true); },"t2").start(); } /** * 通过一个volatile变量实现 */ public static void m1(){ new Thread(() -> { while(true) { if(isStop) { System.out.println("-----isStop = true,程序结束。"); break; } System.out.println("------hello isStop"); } },"t1").start(); //暂停几秒钟线程 try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } new Thread(() -> { isStop = true; },"t2").start(); } }
LockSupport的park与unpark方法
LockSupport它的解决的痛点
-
LockSupport不用持有锁块,不用加锁,程序性能好
-
先后顺序随意,不容易导致卡死(因为unpark获得了一个凭证,之后再调用park方法,就可以名正言顺的凭证消费,故不会阻塞)
-
最多可以持有一个unpark许可,但是有很多park的话会消耗掉很多,所以如果调用两次以上park还是会阻塞
-
代码演示
/* (1).阻塞 (permit默认是O,所以一开始调用park()方法,当前线程就会阻塞,直到别的线程将当前线程的permit设置为1时, park方法会被唤醒,然后会将permit再次设置为O并返回) static void park() static void park(Object blocker) (2).唤醒 static void unpark(Thread thread) (调用unpark(thread)方法后,就会将thread线程的许可permit设置成1(注意多次调用unpark方法,不会累加, permit值还是1)会自动唤醒thread线程,即之前阻塞中的LockSupport.park()方法会立即返回) static void unpark(Thread thread) * */ public class LockSupportDemo { public static void main(String[] args) { Thread t1=new Thread(()->{ System.out.println(Thread.currentThread().getName()+"\t"+"coming...."); LockSupport.park(); /* 如果这里有两个LockSupport.park(),因为permit的值为1,上一行已经使用了permit 所以下一行被注释的打开会导致程序处于一直等待的状态 * */ //LockSupport.park(); System.out.println(Thread.currentThread().getName()+"\t"+"被B唤醒了"); },"A"); t1.start(); //下面代码注释是为了A线程先执行 //try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) {e.printStackTrace();} Thread t2=new Thread(()->{ System.out.println(Thread.currentThread().getName()+"\t"+"唤醒A线程"); //有两个LockSupport.unpark(t1),由于permit的值最大为1,所以只能给park一个通行证 LockSupport.unpark(t1); //LockSupport.unpark(t1); },"B"); t2.start(); } }