一个线程不应该由其他线程来强制中断或停止,而是应该由线程自己自行停止。
实例方法interrupt()仅仅是设置线程的中断状态为true,不会停止线程。
通过检查中断标志位,判断当前线程是否被中断。
静态方法,判断线程是否被中断,并清除当前中断状态
也就是说这个方法做了两件事:
1、返回当前线程的中断状态
2、将当前线程的中断状态设为false
static volatile boolean isStop = false;public static void volatileDemo() {new Thread(() -> {while(true) {if(isStop) {System.out.println("-----程序结束------");break;}System.out.println("------hello-------");}},"t1").start();try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }new Thread(() -> {isStop = true;},"t2").start();}
static AtomicBoolean atomicBoolean = new AtomicBoolean(false);public static void atomicBooleanDemo() {new Thread(() -> {while(true) {if(atomicBoolean.get()) {System.out.println("-----程序结束------");break;}System.out.println("------hello-------");}},"t1").start();try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }new Thread(() -> {atomicBoolean.set(true);},"t2").start();}
public static void m3() {Thread t1 = new Thread(() -> {while (true) {//当前线程判断中断标志if (Thread.currentThread().isInterrupted()) {System.out.println("-----程序结束------");break;}System.out.println("------hello------");}}, "t1");t1.start();try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }new Thread(() -> {//修改t1线程的中断标志位为truet1.interrupt();},"t2").start();}
先说结论:中断只是一种协同机制,只修改中断标识位而已,不会立刻停止线程
public static void stopDemo() {Thread t1 = new Thread(() -> {for (int i = 1; i <= 300; i++) {System.out.println("------i: " + i);}System.out.println("t1.interrupt()调用之后02: "+Thread.currentThread().isInterrupted());}, "t1");t1.start();System.out.println("t1.interrupt()调用之前,t1线程的中断标识默认值: "+t1.isInterrupted());try { TimeUnit.MILLISECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); }//实例方法interrupt()仅仅是设置线程的中断状态位设置为true,不会停止线程t1.interrupt();//活动状态,t1线程还在执行中System.out.println("t1.interrupt()调用之后01: "+t1.isInterrupted());try { TimeUnit.MILLISECONDS.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); }//非活动状态,t1线程不在执行中,已经结束执行了。System.out.println("t1.interrupt()调用之后03: "+t1.isInterrupted());}
还有一种情况:如果线程处于被阻塞状态(例如处于sleep, wait, join 等状态),在别的线程中调用当前线程对象的interrupt方法,那么线程将立即退出被阻塞状态,并抛出一个InterruptedException异常。
public static void stopDemo2() {Thread t1 = new Thread(() -> {while (true) {if (Thread.currentThread().isInterrupted()) {System.out.println("-----isInterrupted() = true,程序结束。");break;}try {Thread.sleep(500);} catch (InterruptedException e) {//线程的中断标志位为false,无法停下,需要再次掉interrupt()设置true//Thread.currentThread().interrupt();e.printStackTrace();}System.out.println("------hello Interrupt");}}, "t1");t1.start();try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); }new Thread(() -> {t1.interrupt();//修改t1线程的中断标志位为true},"t2").start();}
上边不能停止的原因是:
抛出了中断异常后,中断标识也被置为了 false ,导致无限循环,想要解决这个bug,需要在异常中再次中断,也就是打开上边的 //Thread.currentThread().interrupt(); 这句代码。
public static void syncWaitNotify() {new Thread(() -> {//暂停几秒钟线程try { TimeUnit.SECONDS.sleep(3); } 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();//暂停几秒钟线程try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }new Thread(() -> {synchronized (objectLock){objectLock.notify();System.out.println(Thread.currentThread().getName()+"\t"+"---发出通知");}},"t2").start();}
使用总结:
wait和notify方法必须要在同步块或者方法里面,且成对出现使用
需要先 wait 后 notify 才能生效
public static void lockAwaitSignal() {new Thread(() -> {//暂停几秒钟线程try { TimeUnit.SECONDS.sleep(3); } 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();}
使用总结:
Condtion中的线程等待和唤醒方法之前,需要先获取锁
需要先 await 后 signal 才能生效
public static void parkDemo() {Thread t1 = new Thread(() -> {System.out.println(Thread.currentThread().getName() + "\t" + "---come in");LockSupport.park();System.out.println(Thread.currentThread().getName() + "\t" + "---被唤醒");}, "t1");t1.start();new Thread(() -> {LockSupport.unpark(t1);System.out.println(Thread.currentThread().getName()+"\t"+"---发出通知");},"t2").start();}
总结:park() 阻塞线程,unpark(Thread thread) 唤醒线程,不需要像之前那样锁块,也没有先后顺序的要求
注意1:注意多次调用 unpark() 方法,不会累加,permit值最大是1
注意2:一个线程只能发一张通行证,比如 t1 park一次,t2可以 unpark 唤醒,如果 t1 park 了两次,就需要两个线程 t2 park 一次,t3 park 一次,以此类推,一个线程只能唤醒一次阻塞。
下一篇:压缩包加密、解密