JUC编程之——线程中断机制及源码分析

1 什么是中断机制

  • 一个线程不应该由其他线程中断或停止,而应该由线程自行停止——命运掌握在自己手里;
  • 所以Thread.stop、Thread.suspend、Thread.resume方法都已过时;
  • Java中无法立即停止一个线程;
  • Java提供了一种用于停止线程的协商机制——中断,也即中断标识协商机制
  • 中断过程需要程序员自己实现——用线程的interrupt方法将对象的中断标识设置为true——只是温馨提示,不是强制终止;


2 中断的相关API方法之三大方法说明

  • void interrupt():
    • 中断此线程;
    • 只是设置中断标志位,发起一个协商;
  • static boolean interrupted():
    • 测试当前线程是否已被中断;
    • 静态方法;
    • 方法做了两件事:
      • 返回当前线程的中断状态(true/false),测试当前的线程是否已被中断;
      • 将当前线程的中断状态清零并重新设为false,清除线程的中断状态
  • boolean isInterrupted():
    • 判断当前线程是否被中断(通过检查中断标志位);
    • 和第一个方法配合使用;


3 如何停止中断运行中的线程——代码示例

3.1 通过关键字volatile变量实现

import java.util.concurrent.TimeUnit;


public class InterruptDemo
{
    
    
private static volatile boolean isStop = false;

public static void main(String[] args)
{
    
    
    new Thread(() -> {
    
    
        while(true)
        {
    
    
            // 需要退出了 or 需要中断了
            if(isStop)
            {
    
    
                System.out.println(Thread.currentThread().getName()+"线程------isStop = true,自己退出了");
                break;
            }
            System.out.println("-------hello interrupt");
        }
    },"t1").start();

    //暂停几秒钟线程
    try {
    
     TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) {
    
     e.printStackTrace(); }
    isStop = true;
}


3.2 通过AtomicBoolean类实现

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

public class StopThreadDemo
{
    
    
	// init
    private final static AtomicBoolean atomicBoolean = new AtomicBoolean(true);

    public static void main(String[] args)
    {
    
    
        new Thread(() -> {
    
    
            while(true)){
    
    
                if(atomicBoolean.get()){
    
    
                    System.out.println(
                        Thread.currentThread().getName() + "\t atomicBoolean 被修改为true 线程停止"
                    );
                    break;
                }
            
                System.out.println("t1-----hello");
            }
        }, "t1").start();

        // 小睡一会
        try {
    
     TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) {
    
     e.printStackTrace(); }

        // 另一个线程
        new Thread(() -> {
    
    
            atomicBoolean.set(true);
        },"t2").start();
    }
}


}


3.3 通过Thread类自带的中断API方法实现

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

public class InterruptTest {
    
    

    public static void main(String[] args) {
    
    
        Thread t1 = new Thread(() -> {
    
    
            while(true) {
    
    
                // 判断中断
                if(Thread.currentThread().isInterrupted()) {
    
    
                    System.out.println(Thread.currentThread().getName() + "\t 中断");
                    break;
                }

                System.out.println("----t1 interrupt");
            }
        },"t1");
        t1.start();

        try {
    
    
            TimeUnit.MILLISECONDS.sleep(20);
        } catch (InterruptedException e) {
    
    
            throw new RuntimeException(e);
        }

        new Thread(() -> {
    
    
        	// 中断
            t1.interrupt();
        },"t2").start();
    }
}


4 中断方法底层源码分析

4.1 interrupt()方法——无返回值

  • interrupt方法作用:中断此线程;
  • 仅仅是将中断标识位从false设置为true
  • 并不是立刻停止线程
  • 如果线程处于被阻塞状态(例如处于sleep, wait, join 等状态),在别的线程中调用当前线程对象的interrupt方法,那么线程将立即退出被阻塞状态 (不是立刻退出线程),并抛出一个InterruptedException异常。;
  • 中断不活动的线程不会产生任何影响;

方法:

    public void interrupt() {
    
    
        if (this != Thread.currentThread())
            checkAccess();

        synchronized (blockerLock) {
    
    
            Interruptible b = blocker;
            if (b != null) {
    
    
            	// 实际调用interrupt0()
                interrupt0();           // Just to set the interrupt flag
                b.interrupt(this);
                return;
            }
        }
        interrupt0();
    }

调用底层native方法:

    private native void interrupt0();


4.2 isInterrupted()方法

public boolean isInterrupted() {
    
    
        return isInterrupted(false);
    }

底层还是调用native方法:

// Tests if some Thread has been interrupted. 
// The interrupted state is reset or not based on the value of ClearInterrupted that is passed.
    private native boolean isInterrupted(boolean ClearInterrupted);


5 面试题

5.1 案例1

当前线程的中断标识为true,是不是立刻停止?
——不是立刻停止 需要线程自己配合;

扫描二维码关注公众号,回复: 15950293 查看本文章
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

public class InterruptTest {
    
    
    public static void main(String[] args) throws InterruptedException
    {
    
    
        Thread t1 = new Thread(() -> {
    
    
            for (int i=0;i<300;i++) {
    
    
                System.out.println("-------"+i);
            }
            System.out.println("after t1.interrupt()--第2次---: "+Thread.currentThread().isInterrupted());
        },"t1");
        t1.start();

        // 默认是false
        System.out.println("before t1.interrupt()----: "+t1.isInterrupted());

        //实例方法interrupt()仅仅是设置线程的中断状态位设置为true,不会停止线程
        t1.interrupt();

        //活动状态,t1线程还在执行中 
        try {
    
     TimeUnit.MILLISECONDS.sleep(3); } catch (InterruptedException e) {
    
     e.printStackTrace(); }

        // 这里已经是true 但是程序没有立刻中断
        System.out.println("after t1.interrupt()--第1次---: "+t1.isInterrupted());
        //非活动状态,t1线程不在执行中,已经结束执行了。
        
        try {
    
     TimeUnit.MILLISECONDS.sleep(3000); } catch (InterruptedException e) {
    
     e.printStackTrace(); }
        System.out.println("after t1.interrupt()--第3次---: "+t1.isInterrupted());
    }
}


5.2 案例2

  • 问题:线程t1处理阻塞状态(sleep),线程t2调用了t1的interrupt方法,抛出异常后,开始死循环,程序不会结束
  • 解决方法:在catch里再一次调用Thread.currentThread().interrupt();

为什么?

  • 1 在没有调用t1.interrupt()之前,中断标志位默认为false;
  • 2 t2发出中断协商,t1.interrupt(),中断标志位被设置为true;
    • 正常情况下,中断标志位为true,程序停止;
    • 异常情况,t1正在sleep——t1的中断状态将会被清除(从true变为false),并抛出InterrptedException——导致无限循环;
  • 3 在catch块里再次设置:Thread.currentThread().interrupt(); ——防止死循环;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

public class InterruptTest {
    
    
    public static void main(String[] args) {
    
    
        Thread t1 = new Thread(() -> {
    
    
            while(true) {
    
    

                // 中断
                if(Thread.currentThread().isInterrupted()){
    
    
                    System.out.println(Thread.currentThread().getName() + "\t 被设置为true");
                    break;
                }

                // 阻塞 java.lang.InterruptedException: sleep interrupted
                try {
    
    
                    Thread.sleep(200);
                } catch (InterruptedException e) {
    
    
                    // 再调用一次 就不会无限循环了
//                    Thread.currentThread().interrupt();
                    e.printStackTrace();
                }
                System.out.println("----hello");
            }
        }, "t1");

        t1.start();

        try {
    
    
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
    
    
            e.printStackTrace();
        }

        new Thread(() ->
            t1.interrupt(),"t2").start();


    }
}

5.3 案例3

——谈谈对静态方法Thread.interrupted()的理解?

判断线程是否被中断并清除当前中断状态:
● 1 返回当前线程的中断状态,测试当前线程是否已经被中断;
● 2 将当前线程的中断状态清零,重新设置为false,则第二次调用将返回false,两次连续调用结果可能不一样;

public class InterruptTest {
    
    
    public static void main(String[] args) {
    
    

        // main线程 连续两次调用
        System.out.println(Thread.currentThread().getName() + "\t" + Thread.interrupted());
        System.out.println(Thread.currentThread().getName() + "\t" + Thread.interrupted());
        System.out.println("-----------1");
        // 设置中断
        Thread.currentThread().interrupt();
        System.out.println("-----------2");
        // 连续两次调用
        System.out.println(Thread.currentThread().getName() + "\t" + Thread.interrupted());
        System.out.println(Thread.currentThread().getName() + "\t" + Thread.interrupted());
        //        main false
        //        main false
        //                -----------1
        //                -----------2
        //        main true
        //        main false
    }
}

两个底层代码:
两者底层都是调用isInterrupted方法,一个默认为true,一个默认为false;

    public static boolean interrupted() {
    
    
        return currentThread().isInterrupted(true);
    }
    public boolean isInterrupted() {
    
    
        return isInterrupted(false);
    }

猜你喜欢

转载自blog.csdn.net/COINVK/article/details/130107731
今日推荐