多线程基础篇(2)——理解中断
1.何谓线程中断
线程中断,可以理解为一个现成的标识属性,它表示一个运行中的线程是否被其他线程进行了中断操作,中断可以用来进行强制终结线程(使线程进入终止状态),即在执行run方法过程中直接退出(或者说跳过某段代码)。
线程中断的方法:
1)stop()方法:不在使用此方法,其中断线程是立即中断的,即使是在同步代码块中对数据进行操作时也会立即终止,详细不在赘述,只需知道该方法不在使用即可。
2)interrupt()方法:其他线程调用此线程的interrupt()方法对其进行中断操作时,interrupt()方法将线程的中断状态设置为true,如果该线程正处于阻塞或即将处于阻塞状态,则会发生InterruptedException并被抛出,当抛出该异常或使用interrupted()方法判断是否中断时将会重置中断状态为false。
1.1 详解interrupt()方法实现线程中断操作(阻塞线程中断)
1) 当其他线程调用某线程的interrupt()方法时,仅仅时将该线程的中断状态设置为true,并不是一定会立即将该线程中断使其进入终止状态,相当于其他线程对该线程说“兄弟,你要结束了”。如果这个线程处于阻塞或是即将进入阻塞状态时则会发生中断,也可以设置一些中断条件,通过与isInterrupted()方法进行&&操作实现中断。代码如下:
public class Demo8 extends Thread{ public static void main(String[] args) { Demo8 itt = new Demo8(); itt.start(); try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } itt.interrupt(); } public void run() { // 这里调用的是非清除中断标志位的isInterrupted方法 while(!Thread.currentThread().isInterrupted()) { System.out.println(Thread.currentThread().getName() + " 正在运行"); try { System.out.println(Thread.currentThread().getName() + "线程开始阻塞"); Thread.sleep(1000); System.out.println(Thread.currentThread().getName() + " 线程阻塞结束"); } catch (InterruptedException e) { // TODO Auto-generated catch block //由于调用sleep()方法清除状态标志位 所以这里需要再次重置中断标志位 否则线程会继续运行下去 Thread.currentThread().interrupt(); e.printStackTrace(); } } System.out.println("跳出循环"); if (Thread.currentThread().isInterrupted()) { System.out.println(Thread.currentThread().getName() + "线程被中断"); } } }
2)有两种情况无法发生中断:不能中断正在获取synchronized锁或者试图执行IO操作的线程,代码如下
public class Demo9 { public static void main(String[] args) throws Exception { InputStream in=System.in;//不会被中断 Thread t1=new Thread(new IOBlocked(in)); Thread t2=new Thread(new SynchronizedBlocked()); t1.start(); t2.start(); try { Thread.sleep(2000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } t1.interrupt(); t2.interrupt(); } } class IOBlocked implements Runnable{ private InputStream in; public IOBlocked(InputStream is){ in=is; } public void run(){ try{ while(true){ System.out.println("等待进行io操作"); in.read();//试图进行IO操作 } }catch (IOException e) { if(Thread.currentThread().isInterrupted()){ System.out.println("IO thread is Interrupted"); }else{ throw new RuntimeException(e); } } System.out.println("io操作运行中"); } } class SynchronizedBlocked implements Runnable{ public synchronized void f(){ //永不释放锁 while(true){ Thread.yield(); } } public SynchronizedBlocked(){ new Thread(){ public void run(){ SynchronizedBlocked.this.f();//在此线程中获取锁,并且不进行释放 } }.start(); } @Override public void run() { // TODO Auto-generated method stub System.out.println("尝试调用f()"); f();//在此处尝试获取锁 System.out.println("f()运行中"); } }
3)对于无法中断的IO操作,我们可以通过关闭任务中发生阻塞的底层资源,如上代码中的System.in可以通过关闭流的方式来进行中断。
4)对于无法中断互斥所引起的阻塞,我们可以使用ReentrantLock类的tryLock方法或.lockInterruptibly()方法即可解决。
1.2 检查线程中断(实现非阻塞线程中断)
1)当调用某个线程的interrupt方法时,中断发生的唯一时刻是在任务即将进入到阻塞操作中时或者已经在阻塞操作内部,若在某个死循环中添加了可能会产生阻塞操作的代码,但恰巧没有发生任何阻塞的情况下,我们需要另一种方式来退出。
public class InterruptThreadTest extends Thread{ public void run() { // 这里调用的是非清除中断标志位的isInterrupted方法 while(!Thread.currentThread().isInterrupted()) { long beginTime = System.currentTimeMillis(); System.out.println(Thread.currentThread().getName() + "is running"); // 当前线程每隔一秒钟检测线程中断标志位是否被置位 while (System.currentTimeMillis() - beginTime < 1000) {} } if (Thread.currentThread().isInterrupted()) { System.out.println(Thread.currentThread().getName() + "is interrupted"); } } public static void main(String[] args) { // TODO Auto-generated method stub InterruptThreadTest itt = new InterruptThreadTest(); itt.start(); try { Thread.sleep(5000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } // 设置线程的中断标志位 itt.interrupt(); } }
2)检查线程中断的方法:
isInterrupted()方法判断当前线程是否为中断状态
interrupted()方法判断当前线程是否为中断状态,并且会重置线程中断状态为false
3)如何正确的安全的终止线程:中断状态是线程的一个标识位,而中断操作是一种简便的线程间交互 方式,而这种交互方式最适合用来取消或停止任务。除了中断以外,还可以利用一个boolean变 量来控制是否需要停止任务并终止该线程。这种通过标识位或者中断操作的方式能够使线程在终止时有机会去清理资源,而不是武断地将线程停止,因此这种终止线程的做法显得更加安全和优雅。
public class Shutdown { public static void main(String[] args) throws Exception { Runner one = new Runner(); Thread countThread = new Thread(one, "CountThread"); countThread.start(); // 睡眠1秒,main线程对CountThread进行中断,使CountThread能够感知中断而结束 Thread.sleep(1); countThread.interrupt(); Runner two = new Runner(); countThread = new Thread(two, "CountThread"); countThread.start(); // 睡眠1秒,main线程对Runner two进行取消,使CountThread能够感知on为false而结束 Thread.sleep(1); two.cancel(); } private static class Runner implements Runnable { private long i; private volatile boolean on = true; @Override public void run() { while (on && !Thread.currentThread().isInterrupted()) { i++; } System.out.println("Count i = " + i); } public void cancel() { on = false; } } }
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
Python基础系列-用paramiko写一个简单的ssh终端
版权声明:如需转载,请注明转载地址。 https://blog.csdn.net/oJohnny123/article/details/82144008 #!/usr/bin/python # -*- coding: UTF-8 -*- """ Created by liaoyangyang1 on 2017/11/7. """ import paramiko import sys import socket import select from paramiko.py3compat import u tran = paramiko.Transport(('ip', 22,)) tran.start_client() tran.auth_password('username', 'password') # 打开一个通道 chan = tran.open_session() # 获取一个终端 chan.get_pty() # 激活器 chan.invoke_shell() while True: # 监视用户输入和服务器返回数据 # sys.stdin 处理用户输入 # chan 是之前...
- 下一篇
正则表达式总结
创建正则表达式 1.使用RegExp()构造函数来创建 RegExp()构造函数非常有用,特别是在需要动态创建正则表达式的时候,这种情况往往没办法通过写死在代码中的正则表达式直接量来实现。 例如,如果待检索的字符串是由用户输入的,就必须使用RegExp()构造函数,在程序运行时创建正则表达式 var pattern = new RegExp("s$"); 2.使用直接量语法来创建 var pattern = /s$/; RegExp对象的属性 每个RegExp对象(即正则表达式对象)都有5个属性。 属性 属性描述 source 只读的字符串,包含正则表达式的文本 global 只读的布尔值,用以说明这个正则表达式是否带有修饰符g ignoreCase 只读的布尔值,用以说明正则表达式是否带有修饰符i multiline 只读的布尔值,用以说明正则表达式是否带有修饰符m lastIndex 可读/写的整数,如果匹配模式带有g修饰符,这个属性存储在整个字符串中下一次检索的开始位置,这个属性会被exec()和test()方法用到,下面会讲到 直接量字符 字符 匹配 a-zA-Z0-9 匹配自...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
- Jdk安装(Linux,MacOS,Windows),包含三大操作系统的最全安装
- SpringBoot2配置默认Tomcat设置,开启更多高级功能
- SpringBoot2整合Redis,开启缓存,提高访问速度
- CentOS6,CentOS7官方镜像安装Oracle11G
- Windows10,CentOS7,CentOS8安装MongoDB4.0.16
- Red5直播服务器,属于Java语言的直播服务器
- Eclipse初始化配置,告别卡顿、闪退、编译时间过长
- 2048小游戏-低调大师作品