线程中断机制
概念
java提供了一种用于停止线程的协商机制-中断。称为中断标识协商机制。
常用API
- public void interrupt()
仅仅让线程的中断标志位设置为true。不进行其他操作。
- public boolean isInterrupted()
获取中断标志位的状态。
- public static boolean interrupted()
获取中断标志位的状态。并将中断标志位设置为false
如何停止中断运行的线程
volatile变量实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| private static volatile boolean isStop = false; public static void main(String[] args) { new Thread(() -> { while (true) { if (isStop) { System.out.println(Thread.currentThread().getName() + "线程isStop = true,自己退出"); break; } System.out.println("-------hello interrupt--------"); } }, "t1").start(); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } isStop = true; }
|
AtomicBoolean实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| private static final AtomicBoolean atomicBoolean = new AtomicBoolean(true);
public static void main(String[] args) { new Thread(() -> { while (atomicBoolean.get()) { try { TimeUnit.MILLISECONDS.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("-------hello------"); } }).start(); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } atomicBoolean.set(false); }
|
中断API interrupt和isInterrupted
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| public static void main(String[] args) { Thread t1 = new Thread(() -> { while (true) { if (Thread.currentThread().isInterrupted()) { System.out.println("-----t1 线程被中断了,程序结束"); break; } System.out.println("-----hello-------"); } }, "t1"); t1.start(); System.out.println("t1是否被中断:" + t1.isInterrupted()); try { TimeUnit.MILLISECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } t1.interrupt(); System.out.println("t1是否被中断:" + t1.isInterrupted()); }
|
注意
- 如果线程处于正常活动状态,interrupt会将该线程中断状态位设置为true。要想该线程进行进一步处理需要自己根据中断状态为来写业务逻辑。
- 如果线程处于阻塞状态(sleep, wait, join)在别的线程调用当前线程interrupt方法,那么线程立即退出阻塞状态,并抛出InterruptException异常,并将中断标志为清除(置为false)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| Thread t1 = new Thread(() -> { while (true) { if(Thread.currentThread().isInterrupted()) { System.out.println(Thread.currentThread().getName()+"\t " + "中断标志位:"+Thread.currentThread().isInterrupted()+" 程序停止"); break; }
try { Thread.sleep(200); } catch (InterruptedException e) { Thread.currentThread().interrupt(); e.printStackTrace(); }
System.out.println("-----hello InterruptDemo3"); } }, "t1"); t1.start();
try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }
new Thread(() -> t1.interrupt(),"t2").start();
|
拓展:线程有哪些状态?7种状态
创建,就绪(等待CPU),运行,阻塞(等待锁对象),等待(等待事件),超时等待,结束
sleep不会释放锁。wait会释放锁。因此sleep进入等待状态。wait进入阻塞状态。
LockSupport
LockSupport是线程阻塞和唤醒的工具类。主要通过park阻塞和unpark唤醒。
线程等待唤醒机制
Synchronized锁对象的wait和notify
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| Object objectLock = new Object(); new Thread(() -> { try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (objectLock){ System.out.println(Thread.currentThread().getName()+"\t ----come in"); try { objectLock.wait(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"\t ----被唤醒"); } },"t1").start(); new Thread(() -> { synchronized (objectLock){ objectLock.notify(); System.out.println(Thread.currentThread().getName()+"\t ----发出通知"); } },"t2").start();
|
限制:
- 必须在Synchronized同步块中
- wait必须在之前notify。否则通知唤醒会失效。
Lock.condition的await和signal
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| Lock lock = new ReentrantLock(); Condition condition = lock.newCondition(); new Thread(() -> { try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } lock.lock(); try { System.out.println(Thread.currentThread().getName()+"\t ----come in"); condition.await(); System.out.println(Thread.currentThread().getName()+"\t ----被唤醒"); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } },"t1").start(); new Thread(() -> { lock.lock(); try { condition.signal(); System.out.println(Thread.currentThread().getName()+"\t ----发出通知"); }finally { lock.unlock(); } },"t2").start();
|
LockSupport的park和unpark
1 2 3 4 5 6 7 8 9 10 11 12 13
| Thread t1 = new Thread(() -> { try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "\t ----come in"+System.currentTimeMillis()); LockSupport.park(); System.out.println(Thread.currentThread().getName() + "\t ----被唤醒"+System.currentTimeMillis()); }, "t1"); t1.start(); new Thread(() -> { LockSupport.unpark(t1); System.out.println(Thread.currentThread().getName()+"\t ----发出通知"); },"t2").start();
|
优点:
- 不需要在锁块中,本身就可以让线程同步。
- park和unpark不需要有先后顺序。unpark相当于给了park一个凭证。unpark在park执行前也可以让park唤醒。相当于提前给了凭证。(而前面两种就不行)
- 一个park需要一个凭证。但是不同的unpark作用于一个线程只能给一个凭证。(即是连续调用多次unpark和调用一次作用是一样的)