多线程探险——2如何正确的中断线程

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/sui_feng_piao_guo/article/details/102869148

多线程探险——2如何正确的中断java线程

一、内容安排

  1. 什么是守护线程(Daemon Thread)
  2. Join方法的含义
  3. 自己join自己会是什么效果
  4. Interrupt方法
  5. 综合案列:如何去停止线程

二、文章内容

为了能中断线程我们首先需要了解线程中的几个方法, 最后在案列中实现如何正确的停止一个线程; 如果对这几个方法非常熟悉可跳过前面内容直接看综合案列

1. 什么是守护线程(Daemon Thread)

  • 守护线程:从字面意思我们可以感觉到好像是要守护某个事物一样, 实际上简单理解守护线程就是另外一个线程的兄弟(真的做到了不求同年同月同日生,但求同年同月同日死的那种兄弟), 到代码中就是主线程生命周期结束守护线程申明周期跟着结束。

  • 应用场景:心跳检测的场景, 当主线程和另外一台服务器保持长连接的通信时需要定时检测心跳,那么假如主线程停止了心跳检测线程同样应该结束申明周期

  • 代码实现

    • 目标:此处模拟主线程(mian线程)工作10秒, 守护线程是死循环不停的工作
    • 效果:十秒之后主线程生命周期结束,守护线程也随之停止工作
  • 具体代码

    public class DaemonThreadDemo {
    
    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span>String<span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token keyword">throws</span> InterruptedException <span class="token punctuation">{</span>
        <span class="token comment">//1.创建一个守护线程</span>
        Thread daemonThread <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Thread</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-</span><span class="token operator">&gt;</span> <span class="token punctuation">{</span>
            <span class="token keyword">while</span> <span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
                System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"daemon thread is working..."</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token keyword">try</span> <span class="token punctuation">{</span>
                    TimeUnit<span class="token punctuation">.</span>SECONDS<span class="token punctuation">.</span><span class="token function">sleep</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">InterruptedException</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span>
                    e<span class="token punctuation">.</span><span class="token function">printStackTrace</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token punctuation">}</span>
            <span class="token punctuation">}</span>
        <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    
        <span class="token comment">//2.设置daemonThread作为mian的守护线程</span>
        daemonThread<span class="token punctuation">.</span><span class="token function">setDaemon</span><span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">//3.启动守护线程</span>
        daemonThread<span class="token punctuation">.</span><span class="token function">start</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">//4.模拟主线程工作10秒</span>
        TimeUnit<span class="token punctuation">.</span>SECONDS<span class="token punctuation">.</span><span class="token function">sleep</span><span class="token punctuation">(</span><span class="token number">10</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 思考: 如果我不设置daemonThread为面的守护线程他会不会随着main的结束而结束

  • 2.Join方法的含义

    • join:join方法字面意思就是加入, 通俗的理解join方法就是多个线程是一个饭点组合队伍, 有个兄弟A在洗头他喊了你一声等我一下我马上洗完了一起去,这时候你就只能等着他了; 在代码中如果A线程join到B线程那么B线程就会一直等着A线程执行结束后才会执行join后面的代码

    • 应用场景

      • 一个主线程开了三个线程去执行任务, 当三个线程执行完成任务后主线程才能继续执行后续代码
    • 案列步骤

      • 实现在主线程(你自己)中开启一个兄弟线程A
      • 在A中实现洗头十分钟
      • 在主线程中启动A线程, 然后调用A的join方法
      • 在join之后打印兄弟你终于整完了
    • 案列实现

      public class JoinDemo {
          public static void main(String[] args) throws InterruptedException {
              //1.A兄弟线程
              Thread A = new Thread(() -> {
                  for (int i = 0; i < 10; i++) {
                      System.out.println("A兄弟在洗头中");
                      try {
                          TimeUnit.SECONDS.sleep(1);
                      } catch (InterruptedException e) {
                          e.printStackTrace();
                      }
                  }
              });
              //2.A兄弟开始洗头
              A.start();
              //3.A兄弟叫Mian兄弟等她
              A.join();
              //4.A洗完头了
              System.out.println("兄弟你终于洗完头了, 走吧去哪里吃饭!!!");
          }
      }
      
         
         
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21

    3.自己join自己会是什么效果

    • 情景: 假如你当前线程调用了join方法这会有什么效果, 也就是说自己等自己,实际上这是一个死循环程序一直也不会结束;

    • 如何获取当前线程

      Thread yourself = Thread.currentThread();
      
         
         
      • 1
    • 具体代码

      public class JoinYourself {
          public static void main(String[] args) throws InterruptedException {
              Thread yourself = Thread.currentThread();
              yourself.join();
          }
      }
      
         
         
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
    • 最终效果

      • 程序一直不会结束,处于阻塞状态
      • 线程快照如下:
      "main" #1 prio=5 os_prio=0 tid=0x0000000002b13800 nid=0x40f8 in Object.wait() [0x0000000000dcf000]
         java.lang.Thread.State: WAITING (on object monitor)
      	at java.lang.Object.wait(Native Method)
      	- waiting on <0x000000076b105ca0> (a java.lang.Thread)
      	at java.lang.Thread.join(Thread.java:1249)
      	- locked <0x000000076b105ca0> (a java.lang.Thread)
      	at java.lang.Thread.join(Thread.java:1323)
      	at com.huangguoyu.JoinYourself.main(JoinYourself.java:6)
      
         
         
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8

    4.Interrupt方法

    • Interrupt方法:

      • 该方法可以改变线程是否被中断的一个状态值,但是他不会真正的中断线程; 可以通过isInterrupted方法获取这个状态值的改变
      • 调用该方法后如果线程整处于join、sleep、wait状态那么线程会捕获到InterruptedException异常
    • 尝试使用Interrupt中断线程

      • 实际效果是不能终止线程, 程序会一直处于运行状态
      public class InterruptedMethod {
          public static void main(String[] args) {
              Thread thread = new Thread(() -> {
                  while (true) {
      
              <span class="token punctuation">}</span>
          <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
          thread<span class="token punctuation">.</span><span class="token function">start</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
          thread<span class="token punctuation">.</span><span class="token function">interrupt</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
          System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>thread<span class="token punctuation">.</span><span class="token function">isInterrupted</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span>
      

    }

    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
  • 测试线程在sleep状态能不能捕获到InterruptedException异常

    public class InterruptedMethod {
        public static void main(String[] args) {
            Thread thread = new Thread(() -> {
                try {
                    TimeUnit.SECONDS.sleep(100);
                } catch (InterruptedException e) {
                    System.out.println("捕获到了异常!!!");
                    e.printStackTrace();
                }
            });
            thread.start();
            thread.interrupt();
            System.out.println(thread.isInterrupted());
        }
    }
    
      
      
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
  • 5.如何停止线程

    1. 线程的stop方法, 此方法被标记了将被抛弃,此处不再详细介绍
    2. 可以使用状态量flag来停止线程(这里实现方式涉及到java内存模型后续更新)
    3. 首先停止线程我们可以设置线程为某个线程的守护线程只要主线程申明周期结束了守护线程也随之结束了; 那么问题来了我们怎么来控制主线程,实际上我们可以让主线程处于wait、join、sleep状态我们就可以调用主线程的中断方法来结束主线程;那么挖掘机又来了, 主线程执行完守护先成就结束,假如这时候守护线程任务还没有执行完怎么, 好的大家可能想到了join可以让主线程等某个兄弟
    • 案列

      ​ 实现一个线程去执行任务,并且在这个线程中提供中断任务的方法,也就是提供停止执行任务的方法

      • 自定义线程类,并提供execute方法用于执行任务
      • 在run方法中开启一个任务线程去执行任务
      • 在自定义线程类中提供shutdown方法去停止当前线程
      • 测试
    • 案列实现

      
      public class MyIterruptedableThread extends Thread{
      
      <span class="token comment">//需要执行的任务</span>
      <span class="token keyword">private</span> Runnable runnable<span class="token punctuation">;</span>
      
      <span class="token keyword">public</span> <span class="token function">MyIterruptedableThread</span><span class="token punctuation">(</span>Runnable target<span class="token punctuation">)</span> <span class="token punctuation">{</span>
          <span class="token keyword">this</span><span class="token punctuation">.</span>runnable <span class="token operator">=</span> target<span class="token punctuation">;</span>
      <span class="token punctuation">}</span>
      
      <span class="token annotation punctuation">@Override</span>
      <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">run</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
          <span class="token comment">//开启执行任务线程</span>
          Thread task <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Thread</span><span class="token punctuation">(</span>runnable<span class="token punctuation">)</span><span class="token punctuation">;</span>
          <span class="token comment">//设置task线程为当前线程的守护线程</span>
          task<span class="token punctuation">.</span><span class="token function">setDaemon</span><span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
          task<span class="token punctuation">.</span><span class="token function">start</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
          <span class="token comment">//让当前线程等待task线程执行结束</span>
          <span class="token keyword">try</span> <span class="token punctuation">{</span>
              task<span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
          <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">InterruptedException</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span>
              <span class="token comment">//接收到中断异常当前线程执行结束, 其守护线程task也随之结束</span>
              e<span class="token punctuation">.</span><span class="token function">printStackTrace</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
          <span class="token punctuation">}</span>
      <span class="token punctuation">}</span>
      
      <span class="token comment">/**
       * 中断当前线程
       */</span>
      <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">shutDown</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
          <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">interrupt</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span>
      
      <span class="token comment">/**
       * 测试
       */</span>
      <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span>String<span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token keyword">throws</span> InterruptedException <span class="token punctuation">{</span>
          <span class="token comment">//定义任务</span>
          Runnable task <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-</span><span class="token operator">&gt;</span><span class="token punctuation">{</span>
            <span class="token keyword">while</span> <span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
                System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"task is processing..."</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span>
          <span class="token punctuation">}</span><span class="token punctuation">;</span>
          <span class="token comment">//创建主线,控制任务生命周期</span>
          MyIterruptedableThread myIterruptedableThread <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">MyIterruptedableThread</span><span class="token punctuation">(</span>task<span class="token punctuation">)</span><span class="token punctuation">;</span>
          <span class="token comment">//启动线程执行任务</span>
          myIterruptedableThread<span class="token punctuation">.</span><span class="token function">start</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
          <span class="token comment">//执行5秒后中断任务</span>
          TimeUnit<span class="token punctuation">.</span>SECONDS<span class="token punctuation">.</span><span class="token function">sleep</span><span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
          System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"任务执行五秒, 结束任务"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
          myIterruptedableThread<span class="token punctuation">.</span><span class="token function">shutDown</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      
      <span class="token punctuation">}</span>
      

    }

    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
                                    </div>
                <link href="https://csdnimg.cn/release/phoenix/mdeditor/markdown_views-e9f16cbbc2.css" rel="stylesheet">
                    </div>
    
本项目是一个基于SSM(Spring+SpringMVC+MyBatis)框架和Vue.js前端技术的家教平台系统。该系统旨在为家教和学生提供一个便捷、高效的在线交流和预约平台,涵盖了从用户注册登录、个人信息管理、课程发布与搜索、预约与取消预约、评价反馈等一系列功能。 在后台管理方面,系统提供了管理员对用户信息、课程信息、预约记录等进行管理的功能,确保平台的正常运行和数据的准确性。通过Spring框架的依赖注入和AOP特性,实现了业务逻辑的清晰分离和高效处理;SpringMVC则负责处理前端请求和响应,提供友好的用户界面;MyBatis作为ORM框架,简化了数据库操作,提高了数据访问的效率和安全性。 前端部分采用Vue.js框架,结合Vue Router进行页面路由管理,Axios进行HTTP请求,实现了前后端分离的开发模式。Vue.js的组件化开发和响应式数据绑定特性,使得前端页面更加动态和交互性强,提升了用户体验。 数据库设计采用了MySQL,存储了用户信息、课程信息、预约记录等核心数据。通过合理的数据库表结构和索引设计,保证了系统的高效运行和数据的一致性。 该项目不仅适合计算机相关专业的毕设学生参考和学习,也适合Java学习者进行项目实战练习。通过对该项目的深入理解和二次开发,可以实现更多个性化功能,进一步提升技术水平和实践能力。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值