电脑知识|欧美黑人一区二区三区|软件|欧美黑人一级爽快片淫片高清|系统|欧美黑人狂野猛交老妇|数据库|服务器|编程开发|网络运营|知识问答|技术教程文章 - 好吧啦网

您的位置:首頁技術文章
文章詳情頁

詳解Java 線程中斷

瀏覽:99日期:2022-08-16 15:57:54
一、前言

大家肯定都使用過 Java 線程開發(Thread / Runnable),啟動一個線程的做法通常是:

new Thread(new Runnable( @Override public void run() { // todo sth... })).start();

然而線程退出,大家是如何做的呢?一般做法可能不外乎以下兩種:

設置一個標志位:true / false 來退出; 強制退出:thread.stop;(我相信,現在應該沒人會使用這種方式了,因為JDK也很早就廢棄了該方法)

可能還會有人提出,我可以用中斷來退出線程! 我只能說:Too Young Too Simple!中斷并不會使得線程結束而退出,中斷(interrupt)只是喚醒被阻塞的線程而已。

本篇,我們就來好好的聊聊:線程中斷,以及如何正確的使用線程中斷,和正確的線程退出。

二、為何 Thread.stop 被廢棄

This method is inherently unsafe. Stopping a thread with Thread.stop causes it to unlock all of the monitors that it has locked (as a natural consequence of the unchecked ThreadDeath exception propagating up the stack). If any of the objects previously protected by these monitors were in an inconsistent state, the damaged objects become visible to other threads, potentially resulting in arbitrary behavior. Many uses of stop should be replaced by code that simply modifies some variable to indicate that the target thread should stop running. The target thread should check this variable regularly, and return from its run method in an orderly fashion if the variable indicates that it is to stop running. If the target thread waits for long periods (on a condition variable, for example), the interrupt method should be used to interrupt the wait.

以上是官方 JDK 中的源碼注釋說明,其含義如下:

**Thread.stop 方法天生就不安全。**使用該方法來停止線程,將會導致其它因為監視器鎖『監視器我們在 synchronized 中就講過,是 Java 的內置鎖』而被鎖住的線程全部都解鎖!(本質的后果是:沒有檢查的 ThreadDeath 異常會在棧中傳播,因而使得監視器鎖解鎖)。如果任何一個被監視器鎖給鎖住的對象處于一個不一致的狀態,那么其被解鎖后將會被其它線程可見,潛在的結果是產生任何后果。**我們應該使用一個變量來代替使用 stop 方法,告訴目標線程退出『這里就是我們開頭所說的第一種方法,設置一個標志位』。**目標線程應該周期性的檢查這個變量,并根據這個變量來正確的退出 run 方法。如果目標線程處于阻塞/休眠狀態(如:使用 wait、sleep、yield 方法后,線程讓出了 CPU 使用權,進而阻塞/休眠),此時,該標志位變量將不會起作用,那么,應該使用 interrupt 方法來中斷目標線程的阻塞/休眠狀態,將其喚醒!

對于 ThreadDeath 對象,官方還有補充:

線程可以在幾乎任何地方拋出 ThreadDeath 異常。由于這一點,所有的同步方法和(代碼)塊將必須被考慮得事無巨細。 線程在清理第一個 ThreadDeath 異常的時候(在 catch 或 finally 語句中),可能會拋出第二個。清理工作將不得不重復直到到其成功。保障這一點的代碼將會很復雜。

所以,我們也別想著去 try-catch ThreadDeath Exception!

同樣,被廢棄的還有 Thread.resume 和 Thread.suspend。這倆方法有造成死鎖的危險:

使用suspend時,并不會釋放鎖; 如果存在某種情況要先獲取該鎖,再進行resume,那么就造成死鎖了;

取代這兩方法的正確方式是:Object.wait 和 Object.notify :

因為 Object.wait 進入阻塞時,會釋放鎖。

三、線程中斷的含義

Thread 中有三個與中斷相關的方法:

成員方法 interrupt():設置線程中斷標志為 true ; 成員方法 isInterrupted():獲取線程的中斷狀態,默認為 false,調用 interrupt() 后,該方法返回 true; 靜態方法 Thread.interrupted():獲取線程的中斷狀態,并且清除中斷狀態(設置為 false);

注:如果線程中斷后,連續兩次調用 Thread.interrupted(),第一次是 true & 清除狀態,第二次結果是 false。

3.1、初步了解

我們先來通過一個例子來初步了解 thread.interrupt :

public class InterruptDemo implements Runnable { @Override public void run() { while (true) { System.out.println('Thread running...'); } } public static void main(String[] args) throws InterruptedException { Thread thread = new Thread(new InterruptDemo(), 'InterruptDemo'); System.out.println('start thread'); thread.start(); Thread.sleep(50); System.out.println('interrupt thread'); thread.interrupt(); Thread.sleep(50); System.out.println('thread’s status = ' + thread.isInterrupted()); }}

輸出結果:

start threadThread running...Thread running.........interrupt threadThread running...Thread running.........thread’s status = trueThread running.........

我們可以看到,即便我們調用了 thread.interrupt 方法,線程也并沒有退出,仍舊繼續運行。因此,這個例子證明了一點:我們并不能通過'我們所認為的'中斷來試圖'結束'正在運行的線程。

3.2、中斷即喚醒阻塞/休眠的線程

同樣,我們再來看一個例子:

public class InterruptDemo implements Runnable { @Override public void run() { while (true) { System.out.println('Thread will sleep 10s ------------------------- running'); long timestamp = System.currentTimeMillis(); try { Thread.sleep(10000); } catch (InterruptedException e) { System.out.println('thread interrupted...'); } timestamp = System.currentTimeMillis() - timestamp; System.out.println('Thread run, total sleep = ' + timestamp + '(ms)'); } } public static void main(String[] args) throws InterruptedException { Thread thread = new Thread(new InterruptDemo(), 'InterruptDemo'); System.out.println('start thread'); thread.start(); Thread.sleep(3000); System.out.println('interrupt thread'); thread.interrupt(); System.out.println('main exit'); }}

輸出結果:

start threadThread will sleep 10s ------------------------- runninginterrupt threadmain exitthread interrupted...Thread run, total sleep = 3002(ms)Thread will sleep 10s ------------------------- runningThread run, total sleep = 10002(ms)Thread will sleep 10s ------------------------- running

我們可以看到,線程啟動后,進入睡眠(10s),3秒后被中斷喚醒,執行完一個 while 后再次進入第二次睡眠(10s),然后周而復始。

3.3、一般標志位法退出線程

public class InterruptDemo implements Runnable { private static final AtomicBoolean running = new AtomicBoolean(true); @Override public void run() { while (running.get()) { long timestamp = System.currentTimeMillis(); timestamp = System.currentTimeMillis() - timestamp; System.out.println('Thread run, total sleep = ' + timestamp + '(ms)'); } System.out.println('Thread exit'); } public static void main(String[] args) throws InterruptedException { Thread thread = new Thread(new InterruptDemo(), 'InterruptDemo'); System.out.println('start thread'); thread.start(); Thread.sleep(100); System.out.println('interrupt thread'); thread.interrupt(); running.set(false); System.out.println('main exit'); }}

輸出結果:

start thread.......Thread run, total sleep = 0(ms)interrupt threadThread run, total sleep = 0(ms)Thread run, total sleep = 0(ms)Thread run, total sleep = 0(ms)main exitThread exit

我們通過使用一個 AtomicBoolean 變量來當作標志位,使得我們的線程能正常退出。 我們也可以判斷線程是否被中斷而選擇性的退出。

3.4、線程中斷退出

public class InterruptDemo implements Runnable { @Override public void run() { while (!Thread.currentThread().isInterrupted()) { long timestamp = System.currentTimeMillis(); timestamp = System.currentTimeMillis() - timestamp; System.out.println('Thread run, total sleep = ' + timestamp + '(ms)'); } System.out.println('Thread exit'); } public static void main(String[] args) throws InterruptedException { Thread thread = new Thread(new InterruptDemo(), 'InterruptDemo'); System.out.println('start thread'); thread.start(); Thread.sleep(100); System.out.println('interrupt thread'); thread.interrupt(); System.out.println('main exit'); }}

輸出結果:

start thread.......Thread run, total sleep = 0(ms)interrupt threadThread run, total sleep = 0(ms)Thread run, total sleep = 0(ms)Thread run, total sleep = 0(ms)main exitThread exit3.5、標志位 + 線程中斷結合

public class InterruptDemo implements Runnable { private static final AtomicBoolean running = new AtomicBoolean(true); @Override public void run() { while (running.get()) { System.out.println('Thread will sleep 10s ------------------------- running'); long timestamp = System.currentTimeMillis(); try { Thread.sleep(10000); } catch (InterruptedException e) { System.out.println('Interrupted... Todo other things then exit......'); running.set(false); continue; } timestamp = System.currentTimeMillis() - timestamp; System.out.println('Thread run, total sleep = ' + timestamp + '(ms)'); } System.out.println('Thread exit'); } public static void main(String[] args) throws InterruptedException { Thread thread = new Thread(new InterruptDemo(), 'InterruptDemo'); System.out.println('start thread'); thread.start(); Thread.sleep(3000); System.out.println('interrupt thread'); thread.interrupt(); System.out.println('main exit'); }}

輸出結果:

start threadThread will sleep 10s ------------------------- runninginterrupt threadmain exitInterrupted... Todo other things then exit......Thread exit四、總結

本文我們分析了線程的中斷,并讓大家了解了中斷的含義:只是告訴該線程,你被『中斷』了,至于你想干嘛,還是由你自己來決定。同時,我們也簡單分析了幾個廢棄的方法的原因。希望大家學習了本文之后,能正確且合理的設計,線程如何安全的退出。

五、附錄 Object.wait:阻塞當前線程,釋放持有的鎖; Object.notify:喚醒當前對象上被阻塞的線程,使其進入就緒狀態; Object.notifyAll:喚醒所有線程; Thread.sleep:指定當前線程休眠一定時間,讓出CPU,但不會釋放同步資源鎖; Thread.yield:讓出CPU使用權,讓自己和其它線程來爭奪使用CPU的機會,因此,使用此方法后,并不能保證該線程又再次拿到CPU而恢復運行(使用此方法后,優先級高的線程拿到CPU的概率較大,但優先級低的線程也有概率拿到CPU而執行),同理不會釋放同步資源鎖;

以上就是詳解Java 線程中斷的詳細內容,更多關于Java 線程中斷的資料請關注好吧啦網其它相關文章!

標簽: Java
相關文章:
主站蜘蛛池模板: 面粉仓_储酒罐_不锈钢储酒罐厂家-泰安鑫佳机械制造有限公司 | 电销卡_稳定企业大语音卡-归属地可选-世纪通信 | 聚合氯化铝价格_聚合氯化铝厂家_pac絮凝剂-唐达净水官网 | TwistDx恒温扩增-RAA等温-Jackson抗体-默瑞(上海)生物科技有限公司 | 口臭的治疗方法,口臭怎么办,怎么除口臭,口臭的原因-口臭治疗网 | 汽车整车综合环境舱_军标砂尘_盐雾试验室试验箱-无锡苏南试验设备有限公司 | 康明斯发电机,上柴柴油发电机,玉柴柴油发电机组_海南重康电力官网 | 纯化水设备-EDI-制药-实验室-二级反渗透-高纯水|超纯水设备 | 挨踢网-大家的导航! | 耐破强度测试仪-纸箱破裂强度试验机-济南三泉中石单品站 | 防爆型气象站_农业气象站_校园气象站_农业四情监测系统「山东万象环境科技有限公司」 | 能量回馈_制动单元_电梯节能_能耗制动_深圳市合兴加能科技有限公司 | 智能电表|预付费ic卡水电表|nb智能无线远传载波电表-福建百悦信息科技有限公司 | 防堵吹扫装置-防堵风压测量装置-电动操作显示器-兴洲仪器 | 济南网站策划设计_自适应网站制作_H5企业网站搭建_济南外贸网站制作公司_锐尚 | 空气能采暖,热泵烘干机,空气源热水机组|设备|厂家,东莞高温热泵_正旭新能源 | 无刷电机_直流无刷电机_行星减速机-佛山市藤尺机电设备有限公司 无菌检查集菌仪,微生物限度仪器-苏州长留仪器百科 | 2025福建平潭岛旅游攻略|蓝眼泪,景点,住宿攻略-趣平潭网 | 苏州教学设备-化工教学设备-环境工程教学模型|同科教仪 | 膏剂灌装旋盖机-眼药水灌装生产线-西林瓶粉剂分装机-南通博琅机械科技 | 中空玻璃生产线,玻璃加工设备,全自动封胶线,铝条折弯机,双组份打胶机,丁基胶/卧式/立式全自动涂布机,玻璃设备-山东昌盛数控设备有限公司 | 沙盘模型公司_沙盘模型制作公司_建筑模型公司_工业机械模型制作厂家 | 山东PE给水管厂家,山东双壁波纹管,山东钢带增强波纹管,山东PE穿线管,山东PE农田灌溉管,山东MPP电力保护套管-山东德诺塑业有限公司 | 氧化铁红厂家-淄博宗昂化工| 双工位钻铣攻牙机-转换工作台钻攻中心-钻铣攻牙机一体机-浙江利硕自动化设备有限公司 | 科研ELISA试剂盒,酶联免疫检测试剂盒,昆虫_植物ELISA酶免试剂盒-上海仁捷生物科技有限公司 | 大型冰雕-景区冰雕展制作公司,3D创意设计源头厂家-[赛北冰雕] | 楼承板设备-楼承板成型机-免浇筑楼承板机器厂家-捡来 | 新中天检测有限公司青岛分公司-山东|菏泽|济南|潍坊|泰安防雷检测验收 | 手术室净化厂家_成都实验室装修公司_无尘车间施工单位_洁净室工程建设团队-四川华锐16年行业经验 | 江苏皓越真空设备有限公司 | 太平洋亲子网_健康育儿 品质生活| 济南玻璃安装_济南玻璃门_济南感应门_济南玻璃隔断_济南玻璃门维修_济南镜片安装_济南肯德基门_济南高隔间-济南凯轩鹏宇玻璃有限公司 | 安徽净化板_合肥岩棉板厂家_玻镁板厂家_安徽科艺美洁净科技有限公司 | 千淘酒店差旅平台-中国第一家针对TMC行业的酒店资源供应平台 | 深圳装修_店面装修设计_餐厅设计_装修全包价格-尚泰装饰设计 | 非标压力容器_碳钢储罐_不锈钢_搪玻璃反应釜厂家-山东首丰智能环保装备有限公司 | 汕头市盛大文化传播有限公司,www.11400.cc | 真空粉体取样阀,电动楔式闸阀,电动针型阀-耐苛尔(上海)自动化仪表有限公司 | 交通气象站_能见度检测仪_路面状况监测站- 天合环境科技 | 高压贴片电容|贴片安规电容|三端滤波器|风华电容代理南京南山 |