使用interrupt来通知,而不是强制。 那么,interrupt()方法该怎么用呢?interrupt()其本身并不是一个强制打断线程的方法,其仅仅会修改线程的interrupt标志位,然后让线程自行去读标志位,自行判断是否需要中断。
演示一:run方法内没有sleep或wait方法的场景中,停止线程
public class StopThreadWay implements Runnable{
@Override
public void run() {
int num = 0;
while(num <= Integer.MAX_VALUE / 2){
if(num % 10000 == 0){
System.out.println(num+"是10000的倍数");
}
num++;
}
System.out.println("任务运行结束了");
}
public static void main(String[] args) {
Thread thread = new Thread(new StopThreadWay());
thread.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
thread.interrupt();
}
}
运行结果
1073670000是10000的倍数
1073680000是10000的倍数
1073690000是10000的倍数
1073700000是10000的倍数
1073710000是10000的倍数
1073720000是10000的倍数
1073730000是10000的倍数
1073740000是10000的倍数
任务运行结束了
Process finished with exit code 0
为什么没有中断?这是因为这个线程想不想停止取决于人家本身,你强加给它一个中断信号,人家完全有权不做理会。那怎么办?往下看。
public class StopThreadWay implements Runnable{
@Override
public void run() {
int num = 0;
while(num <= Integer.MAX_VALUE / 2 && !Thread.currentThread().isInterrupted()){
if(num % 10000 == 0){
System.out.println(num+"是10000的倍数");
}
num++;
}
System.out.println("任务运行结束了");
}
public static void main(String[] args) {
Thread thread = new Thread(new StopThreadWay());
thread.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
thread.interrupt();
}
}
运行结果
94940000是10000的倍数
94950000是10000的倍数
94960000是10000的倍数
94970000是10000的倍数
94980000是10000的倍数
94990000是10000的倍数
95000000是10000的倍数
95010000是10000的倍数
任务运行结束了
Process finished with exit code 0
在Thread.java类里提供了两种方法判断线程是否为停止的。
this.interrupted(): 测试当前线程是否已经中断(静态方法),如果连续调用该方法,则第二次调用将返回false。在api文档中说明interrupted()方法具有清除状态的功能。执行后具有将状态标识清除为false的功能。
this.isInterrupted(): 测试线程是否已经中断,但是不能清除状态标识。
演示二:线程可能被阻塞的场景中,停止线程
public class StopThreadWay {
public static void main(String[] args) {
Runnable runnable = () -> {
int num = 0;
try{
while (num <= 300 && !Thread.currentThread().isInterrupted()){
if(num % 100 == 0){
System.out.println(num+"是100的倍数");
}
num++;
}
Thread.sleep(1000);
}catch (Exception e){
e.printStackTrace();
}
};
Thread thread = new Thread(runnable);
thread.start();
try {
Thread.sleep(500);
thread.interrupt();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
运行结果
0是100的倍数
100是100的倍数
200是100的倍数
300是100的倍数
java.lang.InterruptedException: sleep interrupted
at java.lang.Thread.sleep(Native Method)
at com.example.demo.stopthreads.StopThreadWay.lambda$main$0(StopThreadWay.java:19)
at java.lang.Thread.run(Thread.java:748)
Process finished with exit code 0
为什么会抛出异常了呢?那是因为当线程正在休眠过程中,如果收到中断信号,sleep会响应中断信号,它响应中断信号的方式非常特殊,即抛出一个异常,此时会被catch捕获。
演示三:如果线程在每次迭代后都阻塞的场景中,停止线程
public class StopThreadWay {
public static void main(String[] args) {
Runnable runnable = () -> {
int num = 0;
try{
while (num <= 10000){
if(num % 100 == 0){
System.out.println(num+"是100的倍数");
}
num++;
Thread.sleep(10);
}
}catch (Exception e){
e.printStackTrace();
}
};
Thread thread = new Thread(runnable);
thread.start();
try {
Thread.sleep(5000);
thread.interrupt();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
运行结果
0是100的倍数
100是100的倍数
200是100的倍数
300是100的倍数
400是100的倍数
java.lang.InterruptedException: sleep interrupted
at java.lang.Thread.sleep(Native Method)
at com.example.demo.stopthreads.StopThreadWay.lambda$main$0(StopThreadWay.java:18)
at java.lang.Thread.run(Thread.java:748)
Process finished with exit code 0
如果在执行过程中,每次循环都会调用sleep或wait等方法,那么不需要每次迭代都检查是否已中断。
演示四:如果while里面放try/catch,会导致中断失效
public class StopThreadWay {
public static void main(String[] args) {
Runnable runnable = () -> {
int num = 0;
while (num <= 10000){
if(num % 100 == 0){
System.out.println(num+"是100的倍数");
}
num++;
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
Thread thread = new Thread(runnable);
thread.start();
try {
Thread.sleep(5000);
thread.interrupt();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
运行结果
0是100的倍数
100是100的倍数
200是100的倍数
300是100的倍数
400是100的倍数
java.lang.InterruptedException: sleep interrupted
at java.lang.Thread.sleep(Native Method)
at com.example.demo.stopthreads.StopThreadWay.lambda$main$0(StopThreadWay.java:18)
at java.lang.Thread.run(Thread.java:748)
500是100的倍数
600是100的倍数
.............
为什么会抛出异常之后继续执行了呢?可能有人会说,加上中断状态判断就好了,行,那我们试试。
public class StopThreadWay {
public static void main(String[] args) {
Runnable runnable = () -> {
int num = 0;
while (num <= 10000 && !Thread.currentThread().isInterrupted()){
if(num % 100 == 0){
System.out.println(num+"是100的倍数");
}
num++;
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
Thread thread = new Thread(runnable);
thread.start();
try {
Thread.sleep(5000);
thread.interrupt();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
运行结果同上,为什么啊?是不是很惊讶啊。那是因为,sleep状态下停止某一个线程,会进入catch语句,并清除状态值,变成false。所以判断就不生效。那该怎么办呢?现在我们进入解决环节。
public class StopThreadWay implements Runnable {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(new StopThreadWay());
thread.start();
Thread.sleep(1000);
thread.interrupt();
}
@Override
public void run() {
while(true && !Thread.currentThread().isInterrupted()){
System.out.println("hello");
try {
throwInMethod();
} catch (InterruptedException e) {
//todo 保存日志,停止服务等操作
e.printStackTrace();
}
}
}
private void throwInMethod() throws InterruptedException {
Thread.sleep(2000);
}
}
public class StopThreadWay implements Runnable {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(new StopThreadWay());
thread.start();
Thread.sleep(1000);
thread.interrupt();
}
@Override
public void run() {
while(true){
if(Thread.currentThread().isInterrupted()){
System.out.println("程序运行结束");
break;
}
throwInMethod();
}
}
private void throwInMethod() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
e.printStackTrace();
}
}
}
运行结果
java.lang.InterruptedException: sleep interrupted
at java.lang.Thread.sleep(Native Method)
at com.example.demo.stopthreads.StopThreadWay.throwInMethod(StopThreadWay.java:32)
at com.example.demo.stopthreads.StopThreadWay.run(StopThreadWay.java:25)
at java.lang.Thread.run(Thread.java:748)
程序运行结束
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.util.channels.InterrupttibleChannel相关方法
java.util.channels.Selector的相关方法