线程停止、中断
原理
使用interrupt方法,去通知而不是强制
public class RightWayStopWithoutSleep implements Runnable {
@Override
public void run() {
int num = 0;
while (!Thread.currentThread().isInterrupted() && num < Integer.MAX_VALUE / 2) {
if (num % 10000 == 0)
System.out.println(num + "是1w的倍数");
num++;
}
System.out.println("任务结束了");
}
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(new RightWayStopWithoutSleep());
thread.start();
Thread.sleep(500);
thread.interrupt();
}
}
注意:
try catch
放到while
外面和里面是不一样的,放到外面可以正常停止,放到里面则无法正常停止。就算补充!Thread.currentThread().isInterrupted()
也没用
因为java的设计思路,如果相应了中断,中断标志就会清空。
正确的方法
遇到中断应该传递给其他函数
public class RightWayStopThreadInProd implements Runnable {
@Override
public void run() {
try {
while (true) {
System.out.println("go");
throwInMethod();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private void throwInMethod() throws InterruptedException {
Thread.sleep(2000);
}
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(new RightWayStopThreadInProd());
thread.start();
Thread.sleep(1000);
thread.interrupt();
}
}
不想或无法传递:恢复中断
public class RightWayStopThreadInProd2 implements Runnable {
@Override
public void run() {
while (true) {
System.out.println("go");
if (Thread.currentThread().isInterrupted()) { //检测
System.out.println("Interupt ed");
break;
}
reInterupt();
}
}
private void reInterupt() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt(); //抛出异常
e.printStackTrace();
}
}
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(new RightWayStopThreadInProd2());
thread.start();
Thread.sleep(1000);
thread.interrupt();
}
}
不能屏蔽中断!!
响应中断的方法总结列表
Object.wait()/wait(long)/wait(long,int)
Thread.sleep(long)/sleep(long,int)
Thread.join()/join(long)/join(long,int)
java.util.concurrent.BlockingQueue.take()/put(E)
java.util.concurrent.locks.Lock.lockInterruptibly()
java.util.concurrent.CountDownLatch.await()
java.util.concurrent.CyclicBarrier.await()
java.util.concurrent.Exchanger.exchange(V)
java.nio.channels.InterruptibleChannel相关方法
java.nio.channels.Selector相关方法
java异常体系
错误方法
- 被弃用的
stop ,suspend,resume
方法- 转账十笔,某一笔突然没了,就容易发生错误。
- suspend是带着锁休息的
- 用volatile设置boolean标记位
volatile设置标记位
package com.hasson.stopthread.volatiledemo;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
//volatile局限性,当线程陷入阻塞的时候,volatile是无法停止的
// 此例中,生产者的生产者速度很快,消费者消费速度很慢。
public class CannotStop {
private volatile boolean canceled = false;
public static void main(String[] args) throws InterruptedException {
ArrayBlockingQueue storge = new ArrayBlockingQueue(10);
Producer producer = new Producer(storge);
Thread producerThread = new Thread(producer);
producerThread.start();
Thread.sleep(1000);
Consumer consumer = new Consumer(storge);
while (consumer.needMoreNums()) {
System.out.println(consumer.storage.take() + "被消费了");
}
System.out.println("消费者不需要更多的数据了");
producer.canceled = true;
System.out.println(producer.canceled);
}
}
class Producer implements Runnable {
BlockingQueue storage;
public volatile boolean canceled = false;
public Producer(BlockingQueue storage) {
this.storage = storage;
}
@Override
public void run() {
int num = 0;
try {
while (num < 10000 && !canceled) {
if (num % 100 == 0) {
System.out.println(num + "被放到了仓库中");
storage.put(num);
//如果这里加入sleep就可以,或者使用interrupt
}
num++;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
System.out.println("生产者停止运行~");
}
}
}
class Consumer {
BlockingQueue storage;
public Consumer(BlockingQueue storage) {
this.storage = storage;
}
public boolean needMoreNums() {
if (Math.random() > 0.95) return false;
return true;
}
}
Interrupt方法解析
- interrupt
- static boolean interrupted
- boolean isInterrupted
- Thread.interrupted()
interrupt
true、false、false、true