并发编程大师系列之:线程的定义和中断 interrupt

1.启动线程的三种方式:

  1.1继承Thread类

    public static class UseThread extends Thread {
        public void run() {
            System.out.println("thread run 执行!");
        }
    }

  启动线程:

UseThread ut = new UseThread();
ut.start();

  1.2实现Runable接口

    public static class UseRun implements Runnable {
        @Override
        public void run() {
            System.out.println("runable run 执行!");
        }
    }

  启动线程

UseRun ur = new UseRun();
new Thread(ur).start();

  1.3实现Callable接口

    public static class UseCall implements Callable<String> {
        @Override
        public String call() throws Exception {
            return "callable call 执行!";
        }
    }

  启动线程

  它是有返回值的,需要用FutureTask来包装,如:

UseCall uc = new UseCall();
FutureTask<String> ft = new FutureTask<>(uc);
new Tread(ft).start();
System.out.println(ft.get());

  返回值需要用Future的get方法来获取。 执行结果:

callable call 执行!

2.使用interrupt来中断线程

先看一段代码

public class InterruptTest01 {

    public static class m1 implements Runnable {

        public void run() {
            try {
                System.out.println("in run() - 睡眠20秒");
                Thread.sleep(20000);
                System.out.println("in run() - 线程唤醒");
            } catch (Exception e) {
                System.out.println("in run() - 线程睡眠中被打断了");
                // 如果没有return,线程不会实际被中断,它会继续打印下面的信息
                System.out.println("t线程sleep中被打断后中断标志位状态:" + Thread.interrupted());
                return;
            }
            System.out.println("in run() - 线程正常的消亡了");
        }
    }

    public static void main(String[] args) {
        m1 si = new m1();
        Thread t = new Thread(si);
        // 开启t线程
        t.start();
        System.out.println("调用interrupt方法前,t线程的中断状态:" + t.isInterrupted());
        try {
            // 仅仅是做标记
            t.interrupt();
            System.out.println("调用interrupt方法后,t线程的中断状态:" + t.isInterrupted());
            // 主线程休眠2秒,从而确保刚才启动的线程有机会执行一段时间
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            System.err.println("主线程catch块出问题了");
        }
        System.out.println("in main() - 主线程终止了");
    }

}

运行的结果:

调用interrupt方法前,t线程的中断状态:false
调用interrupt方法后,t线程的中断状态:true
in run() - 睡眠20秒
in run() - 线程睡眠中被打断了
t线程sleep中被打断后中断标志位状态:false
in main() - 主线程终止了

分析:

分析:Thread.sleep(2000)这个方法需放在interrupt方法之后,如果放在之前,会出现中断标志位全为false的情况。如果只是单纯的调用interrupt()方法,线程并没有实际被中断,会继续往下执行。

比如这样:

public class InterruptTest01 {

    public static class m1 implements Runnable {

        public void run() {
            while (true){
                System.out.println("我是不会中断的了");
            }
        }
    }

    public static void main(String[] args) {
        try {
            m1 si = new m1();
            Thread t = new Thread(si);
            // 开启t线程
            t.start();
            System.out.println("调用interrupt方法前,t线程的中断状态:" + t.isInterrupted());
            // 仅仅是做标记
            t.interrupt();
            System.out.println("调用interrupt方法后,t线程的中断状态:" + t.isInterrupted());
            // 主线程休眠2秒,从而确保刚才启动的线程有机会执行一段时间
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            System.err.println("主线程catch块出问题了");
        }
        System.out.println("in main() - 主线程终止了");
    }

}

它的运行结果就是自旋,应当在run方法中加上中断标志位的判断,如下:

public static class m1 implements Runnable {
        public void run() {
            while (true){
                if(Thread.interrupted()){
                    System.out.println("我竟然中断了");
                    return;
                }
                System.out.println("我是不会中断的了");
            }
        }
    }

再次运行的结果:

调用interrupt方法前,t线程的中断状态:false
调用interrupt方法后,t线程的中断状态:true
我竟然中断了
in main() - 主线程终止了

3.待决中断

意思就是:如果线程在调用sleep()方法前被中断,那么该中断称为待决中断,它会在刚调用sleep()方法时,立即抛出InterruptedException异常。

如下:

public class PendingInterruptTest {

    public static void main(String[] args) {
        Thread.currentThread().interrupt();
        // 获取当前时间
        long startTime = System.currentTimeMillis();
        try {
            Thread.sleep(2000);
            System.out.println("主线程没有被打断");
        } catch (InterruptedException x) {
            System.out.println("主线程被打断,进入catch块");
        }
        // 计算中间代码执行的时间
        System.out.println("时间差 =" + (System.currentTimeMillis() - startTime));
    }

}

运行代码的结果:

主线程被打断,进入catch块
时间差 =1

4.interrupted和isInterrupted的区别?

首先看一段代码

public class InterruptTest01 {

    public static class m1 implements Runnable {
        public void run() {
            System.out.println("我是不会中断的了");
        }
    }

    public static void main(String[] args) {
        try {
            m1 si = new m1();
            Thread t = new Thread(si);
            // 开启t线程
            t.start();
            System.out.println("调用interrupt方法前0,t线程的中断状态:" + t.interrupted());
            t.interrupt();
            System.out.println("调用interrupt方法后1,t线程的中断状态:" + t.interrupted());
            System.out.println("调用interrupt方法后2,t线程的中断状态:" + t.interrupted());
            // 主线程休眠2秒,从而确保刚才启动的线程有机会执行一段时间
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            System.err.println("主线程catch块出问题了");
        }
        System.out.println("in main() - 主线程终止了");
    }

}

运行的结果为:

调用interrupt方法前0,t线程的中断状态:false
调用interrupt方法后1,t线程的中断状态:false
调用interrupt方法后2,t线程的中断状态:false
我是不会中断的了
in main() - 主线程终止了

分析:

结果竟然都是false,可见thread 线程并没有停止,而且调用 thread.interrupted() 结果是两个 false 表示线程一直在运行过程中。官方解释:当前线程是指运行 this.interrupted() 方法的线程 。也就是说,当前线程并不是 t,并不是因为 t 调用了 interrupted() 方法就是当前线程。当前线程一直是 main 线程,它从未中断过,所以打印结果就是两个 false。

改变一下代码:

public class InterruptTest01 {

    public static class m1 implements Runnable {
        public void run() {
            System.out.println("我是不会中断的了");
        }
    }

    public static void main(String[] args) {
        try {
            m1 si = new m1();
            Thread t = new Thread(si);
            // 开启t线程
            t.start();
            System.out.println("调用interrupt方法前0,t线程的中断状态:" + Thread.interrupted());
            Thread.currentThread().interrupt();
            System.out.println("调用interrupt方法后1,t线程的中断状态:" + Thread.interrupted());
            System.out.println("调用interrupt方法后2,t线程的中断状态:" + Thread.interrupted());
            // 主线程休眠2秒,从而确保刚才启动的线程有机会执行一段时间
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            System.err.println("主线程catch块出问题了");
        }
        System.out.println("in main() - 主线程终止了");
    }

}

结果:

调用interrupt方法前0,t线程的中断状态:false
调用interrupt方法后1,t线程的中断状态:true
调用interrupt方法后2,t线程的中断状态:false
我是不会中断的了
in main() - 主线程终止了

分析:

从上述结果中可以看出,方法 interrupted() 的确判断出当前线程是否已经停止,但是为什么第 2 个布尔值是 false 呢?文档中说的很详细,interrupted() 方法具有清除状态的功能,所以第二次的时候返回值是 false。

isInterrupt()方法代码

public static void main(String[] args) {
        try {
            Thread t = Thread.currentThread();
            System.out.println("调用interrupt方法前0,t线程的中断状态:" + t.isInterrupted());
            t.interrupt();
            System.out.println("调用interrupt方法后1,t线程的中断状态:" + t.isInterrupted());
            System.out.println("调用interrupt方法后2,t线程的中断状态:" + t.isInterrupted());
            // 主线程休眠2秒,从而确保刚才启动的线程有机会执行一段时间
            Thread.sleep(2000);
            System.out.println("还在输出吗?");
        } catch (InterruptedException e) {
            System.err.println("主线程catch块出问题了");
        }
        System.out.println("in main() - 主线程终止了");
    }

结果:

调用interrupt方法前0,t线程的中断状态:false
主线程catch块出问题了
调用interrupt方法后1,t线程的中断状态:true
调用interrupt方法后2,t线程的中断状态:true
in main() - 主线程终止了

分析:

线程一旦被中断,isInterrupted()方法便会返回true,而一旦sleep()方法抛出异常,它将清空中断标志,此时isInterrupted()方法将返回false

总结以上:

总结:interrupted():测试 当前线程 是否已经是中断状态,执行后具有清除状态功能。isInterrupted():测试线程 Thread 对象 是否已经是中断状态,但不清除状态标志。

原文地址:https://www.cnblogs.com/zhangjianbing/p/9249938.html

时间: 2024-07-30 07:34:00

并发编程大师系列之:线程的定义和中断 interrupt的相关文章

并发编程大师系列之:Synchronized的类锁和对象锁

说到并发编程,感觉跟大多数人一样,谈之色变,说它简单把,其实很有内容,说难吧,用起来也挺容易,最近我硬着头皮,决心要把并发编程好好的搞一遍.以前,面试的时候,面试官问,并发编程会吗?嗯,接触过,就加一个synchronized关键字就好了,面试官微笑着说,嗯好.特喵的现在感觉来说,这俩low逼.本来写了几行的软文,但感觉在技术文章里面体现,有失风度,明明可以靠文采吃饭,而我却非要靠技术,任性!上代码! 1.对象锁概念: java的所有对象都含有1个互斥锁,这个锁由JVM自动获取和释放.线程进入s

并发编程大师系列之:你真的了解ThreadLocal吗?

总记得在面试的时候被问到过,今天终于轮到你了ThreadLocal,从表面上读英文的意思为线程本地变量,这样也许更好理解了,就是每个线程自己独有的,不与其它线程共享的变量呗. 首先翻开源码,这个author的名字真的熟悉,对,就是dog李(Doug Lea),貌似lang包下的很多都是由这位哥编写的,看一下这个类中的结构(JDK1.8) 常用的就这几个,俩内部类,四个方法. 1. get()方法是用来获取ThreadLocal在当前线程中保存的变量副本. 2. set()用来设置当前线程中变量的

并发编程大师系列之:wait/notify/notifyAll/condition

先把例子写出来,有空再补充... /** * @author itachi * @Title: Express * @Description: 快递类 * @date 2018/7/4下午10:27 */ public class Express { // 始发地 private final static String CITY = "ShangHai"; // 里程变化 private int km; // 地点变化 private String site; Express() {

Java并发编程 - 逐级深入 看线程的中断

最近有足够的空闲时间 去东看看西看看,突然留意到在Java的并发编程中,有关线程中断的,以前初学时一直没弄清楚的一些小东西. 于是,刚好把收获简单的总结一下,通过此文来总结记录下来. 从源码看线程的状态 在开始分析线程的中断工作之前,我们肯定要先留意一个点,那就是肯定是有开启,才会有与之对应的中断工作出现. 开启一个线程的工作,相信每个Javaer都烂熟于心.它很简单,new一个thread对象,然后调用start方法开启线程. 那么,一个好玩的问题就出现了:既然开启一个线程的步骤如此简单明了,

【转】Java并发编程:如何创建线程?

一.Java中关于应用程序和进程相关的概念 在Java中,一个应用程序对应着一个JVM实例(也有地方称为JVM进程),一般来说名字默认是java.exe或者javaw.exe(windows下可以通过任务管理器查看).Java采用的是单线程编程模型,即在我们自己的程序中如果没有主动创建线程的话,只会创建一个线程,通常称为主线程.但是要注意,虽然只有一个线程来执行任务,不代表JVM中只有一个线程,JVM实例在创建的时候,同时会创建很多其它的线程(比如垃圾收集器线程). 由于Java采用的是单线程编

Java并发编程:进程和线程

.title { text-align: center } .todo { font-family: monospace; color: red } .done { color: green } .tag { background-color: #eee; font-family: monospace; padding: 2px; font-size: 80%; font-weight: normal } .timestamp { color: #bebebe } .timestamp-kwd

并发编程之进程与线程

并发编程之进程与线程 2.1 线程与进程 2.1.1 进程 2.1.2 线程 2.1.3 二者对比 2.2 并行与并发 2.3 应用 2.1 线程与进程 2.1.1 进程 程序指令和数据组成,但这些指令要运行,数据要读写,就必须将指令加载至CPU,数据加载至内存.在指令运行过程中还需要用到磁盘.网络等设备.进程就是用来加载指令.管理内存.管理IO的. 当一个程序被运行,从磁盘加载这个程序的代码至内存,这时就开启了一个进程. 进程就可以视为程序的一个实例.大部分程序可以同时运行多个实例进程(例如记

走近并发编程之一 进程和线程

并发与并行,进程与线程不仅是操作系统中及其重要的概念,也是并发编程入门 必须要理解的核心知识. 什么是并发?并发与并行的区别 顺序编程:程序中的所有事物在任意时刻都只能执行一个步骤 并发:在同一时间段内,需要处理多个任务,而在每个时间点又只能处理一个,这就是并发. 假设我们要把多个任务分配给处理机,如果这台机器有多个处理器,显然可以同时执行这些任务,这就是并行. 不同于并行,并发的目的旨在最大限度的提高程序在单处理器上的效率.前者是在物理上的同时发生,而并发是在逻辑上的同时发生.如图,如果要在同

并发编程—— Java 内建线程机制【上】

不理解多线程程序设计, 就无法真正理解 JavaSE 和 JDK 源码: 因为线程特性已经与Java 语言紧密地融合在一起. 如何学习多线程程序设计呢? 那看上去似乎总是显得有些神秘.首先, 必须透彻理解并发程序设计的基本原理和机制, 否则, 只是学习使用那些关键字.类的招式,恐怕只能获得Superficial 的认识, 因为多线程程序设计的难点就在于,在任何情况下都能正确工作, easily writing programs that appear to work but will fail