首页 > 编程语言 >JUC并发编程(3)—锁中断机制

JUC并发编程(3)—锁中断机制

时间:2023-07-21 20:57:36浏览次数:52  
标签:JUC Thread 中断 编程 并发 线程 println true out

目录
学习视频:https://www.bilibili.com/video/BV1ar4y1x727

1.什么是中断

  1. 一个线程不应该由其他线程来强制中断或停止,而是应该由线程自己自行停止,所以,Thread.stop、Thread.suspend、Thread. resume都已经被废弃了
  2. 在Java中没有办法立即停止一条线程,然而停止线程却显得尤为重要,如取消一个耗时操作。因此,Java提供了一种用于停止线程的机制——中断
  3. 中断只是一种协作机制,Java没有给中断增加任何语法,中断的过程完全需要程序员自己实现
  4. 若要中断一个线程,你需要手动调用该线程的interrupt方法,该方法也仅仅是将线程对象的中断标识设为true
  5. 每个线程对象中都有一个标识,用于标识线程是否被中断;该标识位为true表示中断,为false表示未中断;通过调用线程对象的interru pt方法将线程的标识位设为true;可以在别的线程中调用,也可以在自己的线程中调用
    (简而言之就是怎么让一个线程中断停止!)

2.源码解读(中断的相关API)

①. void interrupt( )实例方法
interrupt( )仅仅是设置线程的中断状态未true,不会停止线程
源码解读
(如果这个线程因为wait()、join()、sleep()方法在用的过程中被打断(interupt),会抛出Interrupte dException)
在这里插入图片描述
在这里插入图片描述

②. boolean isInterrupted( )实例方法
判断当前线程是否被中断(通过检查中断标识位) 实例方法
在这里插入图片描述

③. static boolean interrupted( )静态方法

  • 判断线程是否被中断,并清楚当前中断状态,这个方法做了两件事
    (返回当前线程的中断状态 | 将当前线程的中断状态设为false)

原理:假设有两个线程A、B,线程B调用了interrupt方法,这个时候我们连接调用两次isInterrupted方法,第一次会返回true,然后这个方法会将中断标识位设置位false,所以第二次调用将返回false

在这里插入图片描述

  System.out.println(Thread.currentThread().getName()+"---"+Thread.interrupted());
  System.out.println(Thread.currentThread().getName()+"---"+Thread.interrupted());
  System.out.println("111111");
  Thread.currentThread().interrupt();///----false---> true
  System.out.println("222222");
  System.out.println(Thread.currentThread().getName()+"---"+Thread.interrupted());
  System.out.println(Thread.currentThread().getName()+"---"+Thread.interrupted());
  /**
   main---false
   main---false
   111111
   222222
   main---true
   main---false
   * */

④. 比较静态方法interrupted和实例方法isInterrupted

  • 静态方法interrupted将会清除中断状态(传入的参数ClearInterrupted位true)
  • 实例方法isInterrupted则不会(传入的参数ClearInterrupted为false)

3.如何使用中断标识停止线程

  • 在需要中断的线程中不断监听中断状态,一旦发生中断,就执行型对于的中断处理业务逻辑

三种中断标识停止线程的方式

  1. 通过一个volatile变量实现
  2. 通过AtomicBoolean
  3. 通过Thread类自带的中断API方法实现
public class InterruptDemo{
    static volatile boolean isStop = false;
    static AtomicBoolean atomicBoolean = new AtomicBoolean(false);

    public static void m3(){
    Thread t1 = new Thread(() -> {
        while (true) {
            if (Thread.currentThread().isInterrupted()) {
                System.out.println("-----isInterrupted() = true,程序结束。");
                break;
            }
            System.out.println("------hello Interrupt");
        }
    }, "t1");
    t1.start();

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

    new Thread(() -> {
        t1.interrupt();//修改t1线程的中断标志位为true
    },"t2").start();
}

    /**
     * 通过AtomicBoolean
     */
    public static void m2(){
        new Thread(() -> {
            while(true)
            {
                if(atomicBoolean.get())
                {
                    System.out.println("-----atomicBoolean.get() = true,程序结束。");
                    break;
                }
                System.out.println("------hello atomicBoolean");
            }
        },"t1").start();

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

        new Thread(() -> {
            atomicBoolean.set(true);
        },"t2").start();
    }

    /**
     * 通过一个volatile变量实现
     */
    public static void m1(){
        new Thread(() -> {
            while(true)
            {
                if(isStop)
                {
                    System.out.println("-----isStop = true,程序结束。");
                    break;
                }
                System.out.println("------hello isStop");
            }
        },"t1").start();

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

        new Thread(() -> {
            isStop = true;
        },"t2").start();
    }
}

当前线程的中断标识为true,是不是就立刻停止?

  1. 线程调用interrupt()时
  • 如果线程处于正常活动状态,那么会将线程的中断标志设置位true,仅此而已。被设置中断标志的线程将继续正常运行,不受影响。所以,interrupt( )并不能真正的中断线程,需要被调用的线程自己进行配合才行
  • 如果线程处于被阻塞状态(例如处于sleep、wait、join等状态),在别的线程中调用当前线程对象的interrupt方法,那么线程立即被阻塞状态,并抛出一个InterruptedException异常)
  1. 中断只是一种协同机制,修改中断标识位仅此而已,不是立即stop打断
  2. sleep方法抛出InterruptedException后,中断标识也被清空置为false,我们在catch没有通过调用th.interrupt( )方法再次将中断标识位设置位true,这就是导致无限循环了
    public static void m5()
   {
       Thread t1 = new Thread(() -> {
           while (true) {
               if (Thread.currentThread().isInterrupted()) {
                   System.out.println("-----isInterrupted() = true,程序结束。");
                   break;
               }
               try {
                   Thread.sleep(500);
               } catch (InterruptedException e) {
                   //线程的中断标志位重新设置为false,无法停下,需要再次掉interrupt()设置true
                   Thread.currentThread().interrupt();//???????
                   e.printStackTrace();
               }
               System.out.println("------hello Interrupt");
           }
       }, "t1");
       t1.start();

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

       new Thread(() -> {
           t1.interrupt();//修改t1线程的中断标志位为true
       },"t2").start();
   }

   /**
    *中断为true后,并不是立刻stop程序
    */
   public static void m4()
   {
       //中断为true后,并不是立刻stop程序
       Thread t1 = new Thread(() -> {
           for (int i = 1; i <= 300; i++) {
               System.out.println("------i: " + i);
           }
           System.out.println("t1.interrupt()调用之后02: "+Thread.currentThread().isInterrupted());
       }, "t1");
       t1.start();

       System.out.println("t1.interrupt()调用之前,t1线程的中断标识默认值: "+t1.isInterrupted());
       try { TimeUnit.MILLISECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); }
       //实例方法interrupt()仅仅是设置线程的中断状态位设置为true,不会停止线程
       t1.interrupt();
       //活动状态,t1线程还在执行中
       System.out.println("t1.interrupt()调用之后01: "+t1.isInterrupted());

       try { TimeUnit.MILLISECONDS.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); }
       //非活动状态,t1线程不在执行中,已经结束执行了。
       System.out.println("t1.interrupt()调用之后03: "+t1.isInterrupted());
   }

标签:JUC,Thread,中断,编程,并发,线程,println,true,out
From: https://www.cnblogs.com/gen1us/p/17572374.html

相关文章

  • linux系统编程学习笔记
    IO当系统调用io与标准io都能完成相同功能时,优先使用标准io因为不同操作系统提供的系统调用不同,但标准io是之上的封装,不会随着系统的不同改变另外标准io可以合并系统调用,加速如标准io如fopen,在linux下依赖open,在windows下依赖openfile标准IO与系统IO区别一个吞吐量大(即先缓存......
  • (转)数据库锁 sql 数据库大并发操作 数据库原子操作
    1数据库大并发操作要考虑死锁和锁的性能问题。看到网上大多语焉不详(尤其更新锁),所以这里做个简明解释,为下面描述方便,这里用T1代表一个数据库执行请求,T2代表另一个请求,也可以理解为T1为一个线程,T2为另一个线程。T3,T4以此类推。下面以SQLServer(2005)为例。2共享锁(Sharedl......
  • Untiy 网络编程-深入了解TCP
    1.从TCP到物理层应用层:应用层是给应用程序提供功能的。在发送{hello}的例子里面,计算机会把hello转化为二进制然后发送到传输层。传输层:在收到二进制数据后,传输层协议会对它进行一系列的加工,并提供数据流传送、可靠性校验,流量控制。又由于网络层的IP包......
  • 多语言高并发接入阿里巴巴电商平台,获取实时商品详情数据源码,API接口技术开发分享
    接口数据展示alibaba.item_get-获得商品详情公共参数请求地址:注册key和secret接入请私信名称类型必须描述keyString是调用key(必须以GET方式拼接在URL中)secretString是调用密钥api_nameString是API接口名称(包括在请求地址中)[item_search,item_get,item_search_shop等]cacheString......
  • 多语言高并发接入阿里巴巴电商平台,获取实时商品详情数据源码,API接口技术开发分享
    接口数据展示alibaba.item_get-获得商品详情公共参数请求地址:注册key和secret接入名称类型必须描述keyString是调用key(必须以GET方式拼接在URL中)secretString是调用密钥api_nameString是API接口名称(包括在请求地址中)[item_search,item_get,item_sear......
  • Java并发处理任务
    背景当一个任务执行时间过长的时候,并且这个任务可以分解成多个独立的任务时,可以使用Java多线程来减少执行时间。第一版publicstaticvoidmain(String[]args)throwsExecutionException,InterruptedException{func1();}privatestaticvoidfunc1()t......
  • 电子书下载 免费pdf Python编程从入门到实践 第2版
    电子书下载-Python编程从入门到实践第2版简介Python是一种简单易学的编程语言,广泛应用于数据分析、人工智能、Web开发等领域。《Python编程从入门到实践》是一本非常受欢迎的Python入门教程。本文将介绍如何下载免费的PDF版本的第2版《Python编程从入门到实践》电子书,并提供一......
  • 【雕爷学编程】Arduino动手做(49)---有源和无源蜂鸣器模块5
    37款传感器与模块的提法,在网络上广泛流传,其实Arduino能够兼容的传感器模块肯定是不止37种的。鉴于本人手头积累了一些传感器和执行器模块,依照实践出真知(一定要动手做)的理念,以学习和交流为目的,这里准备逐一动手试试多做实验,不管成功与否,都会记录下来——小小的进步或是搞不掂的问题......
  • python斐波那契数列兔子编程
    Python斐波那契数列兔子编程引言斐波那契数列是一个非常经典的数学问题,也是编程中常见的例题之一。它的起源可以追溯到古希腊数学家斐波那契(Fibonacci),他在13世纪的《算盘书》中首次提出了这个数列。斐波那契数列具有很多有趣的特性,而且在计算机科学中有广泛的应用。本文将通过Pyt......
  • 【Java编程教程】详解Java 中的对象和类
    在本页中,我们将了解Java对象和类。在面向对象的编程技术中,我们使用对象和类来设计程序。Java中的对象既是物理实体又是逻辑实体,而Java中的类只是逻辑实体。什么是Java中的对象具有状态和行为的实体称为对象,例如椅子、自行车、记号笔、笔、桌子、汽车等。它可以是物理的或逻辑......