理解多线程的中断方法及synchronized缺陷

public class SynchronizedDefect {

    public synchronized void method(){
        try {
            System.out.println(Thread.currentThread().getName() + "进来了");
            TimeUnit.SECONDS.sleep(10);
            System.out.println(Thread.currentThread().getName() + "结束了");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }


    public static void main(String[] args) throws InterruptedException{

        SynchronizedDefect defect = new SynchronizedDefect();
        Thread t1 = new Thread(defect::method,"线程一");
        t1.start();
        Thread t2 = new Thread(defect::method,"线程二");
        t2.start();
        System.out.println(t2.isInterrupted());//false
        t2.interrupt();// interupt相当于提前中断了t2的阻塞,会修改interupt标识,所以一进入该休眠方法立即进入异常
        // t2.interrupted();//系统随机会启动一个线程执行method方法,假设t1先被执行,t2方法都没睡眠,只是阻塞状态(外面候着),所以不会进入中断异常
        System.out.println(t2.isInterrupted());//interrupted:false    interrupt:true

    }


}

情况一:分别调用两个线程启用method睡眠方法。首先系统随机先执行一个线程t1或t2,我这里就假设执行t1先,后面执行t2.此时t2线程可不会傻傻的等10s,因为自身也是一个线程,除非前面有个10s的阻塞如:Thread.sleep(10s)或者将t2.join(),将t2加入到当前线程(main),让main阻塞。假设执行t2.interrupt()  会打印如下信息:

线程一进来了
false
true
线程一结束了
线程二进来了
java.lang.InterruptedException: sleep interrupted

分析也很简单:

首先线程1进入阻塞方法,线程2在外面候着等锁。线程2强行中断阻塞,并且修改了 interrupt标识改为true,而此时线程1走完,线程2粉墨登场(就他一个线程了,无人争抢),进入可中断的方法sleep,会捕捉到interrupt标识改变(设置了interrupt),会立即进入异常,并修改interrupt标识。

另外一种情况分析:

线程一进来了
false
false
线程一结束了
线程二进来了
线程二结束了

注释这条//t2.interrupt();改用t2.interrupted()会发现又有不同,其实也好理解,首先线程1进入睡眠,将线程2标识中断,此时线程本来就是false,根本没有在睡眠,只是阻塞状态,没有可中断的方法自然是无效的,所以后面执行依然是false,并不会修改interrupt标识。

现在回到情况一:已看出当线程一进入阻塞,线程二只能干巴巴的在那里等着,而且我们试图强行打断在外苦苦等候的线程二,发现线程抛出异常,而抛出异常也是线程一走完,线程二进入该同步方法才抛出的异常,也就意味着线程二还是没有被打断,因为syncronized并没有像sleep或者wait一样捕获interrupt标识的能力。总结两点synchronize缺陷:1无法控制阻塞时长  2阻塞不可被中断。

学习总结:

this.isInterrupted()
检测调用该方法的线程是否被中断,中断状态不会被清除。线程一旦被中断,该方法返回true,而一旦sleep等方法抛出异常,它将清除中断状态,此时方法将返回false。

Thread.interrupted()
检测当前线程是否被中断,并且中断状态会被清除(即重置为false);由于它是静态方法,因此不能在特定的线程上使用,只能报告调用它的线程的中断状态;如果该方法被调用两次,则第二次一般是返回false,如果线程不存活,则返回false

public class Test {
    public static void main(String[] args) {
        System.out.println("1: " + Thread.interrupted());//false
        Thread.currentThread().interrupt();
        System.out.println("2: " + Thread.interrupted());//true
        System.out.println("3: " + Thread.interrupted());//false
    }
}

猜你喜欢

转载自blog.csdn.net/qq_40826106/article/details/85420567