大飞老师带你再看Java线程(三)

本篇我们来聊一下线程中断。
线程中断大体分3种情况:
1>中断当前处于运行状态的线程
2>中断当前处于阻塞状态的线程
3>无法中断持有同步锁的线程

实现机制

java 线程实现中断机制原理其实不难理解:
java 给每一个线程都设置一个boolean类型中断标识,用来标明当前线程是否请求中断。当线程对象调用interrupt() 方法时,会将当前线程标识置为false。表示请求中断此线程。 注意此时仅仅是标记要中断,但不会执行任何动作。在编码时,我们可以在run方法中加入人为控制逻辑, 通过调用Thread.currentThread().isInterrupted()或者Thread.interrupted()来检测线程的中断标识是否被置位,进而实现线程中断控制。

第一种:中断当前处于运行状态的线程

例:线程正常执行某个逻辑,条件改变,需要取消任务执行

public class MyThread1 extends  Thread {
    public void run() {
        while(!Thread.currentThread().isInterrupted()){
            System.out.println("线程正在正常执行.....");
        }
        System.out.println("线程结束....");
    }
}
public static void main(String[] args) throws InterruptedException {
        MyThread1 thread = new MyThread1();
        thread.start();
        //模拟三秒后条件不满足,停止线程
        Thread.sleep(3000);
        //设置中断标志
        thread.interrupt();
    }

在main方法启动MyThread1线程, 线程正常执行,3秒之后,对MyThread1线程发起中断请求。在MyThread1线程run方法中,循环检查中断标识,Thread.currentThread().isInterrupted()一但监测到线程中断请求,立马终止循环,结束线程。

第二种:中断当前处于阻塞状态的线程

例:线程休眠等待条件满足,当条件提前满足,马上中断休眠,开始执行

public class MyThread2 extends  Thread {
    public void run() {
        while(true){
            if(!Thread.currentThread().isInterrupted()){
                try {
                    System.out.println("线程休眠中等待资源.....");
                    Thread.sleep(10000);
                } catch (InterruptedException e) {
                    System.out.println("结束休眠");
                    e.printStackTrace();
                    Thread.currentThread().interrupt();
                }
            }
            System.out.println("正常运行.....");
        }
    }
}
public static void main(String[] args) throws InterruptedException {
        MyThread2 thread = new MyThread2();
        thread.start();
        //模拟三秒后条件提前满足,终止休眠继续执行线程
        Thread.sleep(3000);
        //设置中断标志
        thread.interrupt();
    }

在main方法中启动MyThread2线程,线程开始执行,遇到sleep方法然后阻塞10s,此时的main方法阻塞3s时间到,醒来调用interrupt()给MyThread2线程设置了请求中断标识(false),与此同时,MyThread2立马醒来,先将中断标识复位(true), 然后抛出一个中断异常InterruptedException 。这里要注意,在catch中需要对线程再发起一次中断请求,否则逻辑又进入修改状态。

注意:

除了hread.sleep()方法之外,还有Thread.join()、object.wait()或者调用阻塞的i/o等,注意,IO抛出的不是InterruptedException 而是其他异常,而且在被中断的情况下也不会退出阻塞状态.

第三种:无法中断持有同步锁的线程

例:线程死锁时请求中断

public class Resouces{
    //线程1线程2争夺lock1 跟 lock2,
    //程序中线程1持有lock1,等lock2, 线程2持有lock2,等lock1相互等待,遍死锁了
   public void doSomething(Object lock1, Object lock2){
       //持有1锁
       synchronized (lock1){
           System.out.println(Thread.currentThread().getName() + ",进来了....");
           try {
               //暂停一下效果更明显
               Thread.sleep(100);
           } catch (InterruptedException e) {
               e.printStackTrace();
           }
           //持有2锁
           synchronized (lock2){
               System.out.println(Thread.currentThread().getName() + ",也进来了....");
               System.out.println("正常执行....");
           }
       }
   }
}
public static void main(String[] args) throws InterruptedException {

        //共享资源
        final Resouces resouces = new Resouces();
        //互相锁
        final Object lock1 = new Object();
        final Object lock2 = new Object();

        //线程1
        Thread t1 = new Thread(new Runnable() {
            public void run() {
                //持有2把锁时才可执行
                resouces.doSomething(lock1, lock2);
            }
        },"t1");
        //线程2
        Thread t2 = new Thread(new Runnable() {
            public void run() {
                //持有2把锁时才可执行
                resouces.doSomething(lock2, lock1);
            }
        },"t2");

        //线程启动
        t1.start();
        t2.start();

        Thread.sleep(3000);

        //暂停3s后,给线程发起中断请求
        t1.interrupt();
        t2.interrupt();

    }
注意

线程之所以无法中断,原因在于在线程死锁后,线程都进入了阻塞状态,按照常规的中断机制无法完成中断操作,所以说无法中断。但无绝对如果采用带有超时机制获取方式:reentrantLock.tryLock(longtimeout, TimeUnit unit),等待时间内,如果线程发起中断请求,还是会抛一个InterruptedException , 这样依然可以控制线程中断。


猜你喜欢

转载自blog.csdn.net/wolfcode_cn/article/details/80900881
今日推荐