摘要:另外一種方法是,將這個(gè)線程加入一個(gè)線程組,在線程組里重寫方法來處理拋出的異常,這時(shí)線程組的作用相當(dāng)于實(shí)現(xiàn)了的類。使用對(duì)象處理異常格式錯(cuò)誤使用線程組處理異常測(cè)試異常
感性地理解一下什么是線程?
線程這個(gè)概念其實(shí)是比較抽象的,雖然依照教科書上的說法:
進(jìn)程是從系統(tǒng)獲取資源的最小單位,線程是程序執(zhí)行的最小單位。程序是靜態(tài)存在于磁盤上的一段文本,進(jìn)程運(yùn)行這段文本記錄的命令。
也就是說,進(jìn)程從系統(tǒng)那里獲取到了一定的CPU占用時(shí)間片、內(nèi)存單元和IO等等資源,然后線程將這些資源利用起來執(zhí)行程序,線程執(zhí)行程序是什么意思呢?就是把程序記錄的那些命令逐條依序一步步在CPU上運(yùn)作,數(shù)據(jù)在內(nèi)存、IO上流轉(zhuǎn),將命令執(zhí)行完。
這個(gè)層級(jí)的概念存在于OS上,OS的調(diào)度抽象層級(jí)并不是那么直觀,如果我們?cè)谡f明白一點(diǎn),在做底層的計(jì)算機(jī)組成原理實(shí)驗(yàn)的時(shí)候,在我們接好連線后硬件就具有了處理數(shù)據(jù)的能力,只要扳動(dòng)不同的開關(guān)就可以將數(shù)據(jù)讀寫在不同的芯片上,我們的程序也許是為了完成數(shù)據(jù)流轉(zhuǎn)寫在紙上的扳動(dòng)不同開關(guān)的序列,所以程序是屬于IO級(jí)別的,然后我們依照紙上的命令序列實(shí)際上手去扳動(dòng)不同的開關(guān)執(zhí)行的就是這段程序,所以我們自己充當(dāng)?shù)慕巧褪沁M(jìn)程,最終就得出了這樣的結(jié)論:進(jìn)程“執(zhí)行”程序。至于線程呢,可以看作是進(jìn)程在執(zhí)行過程中的策略,比如說在一個(gè)人扳動(dòng)開關(guān)的時(shí)候就是單進(jìn)程單線程,如果是兩個(gè)人扳動(dòng)開關(guān)就是單進(jìn)程多線程,如果兩個(gè)人能配合起來扳動(dòng)開關(guān)就是多線程同步,所以線程和進(jìn)程之間并非互斥的概念,而是相容的概念,如果有線程就一定有進(jìn)程,一個(gè)進(jìn)程包含了至少一個(gè)的線程。
創(chuàng)建線程的方法
1.創(chuàng)建直接創(chuàng)建Thread的子類,重寫run()方法;
class MyThread extends Thread { @Override public void run() { System.out.println("This is my thread"); } } public class Test { public static void main(String[] args) { MyThread thread = new MyThread(); thread.start(); } }
2.創(chuàng)建一個(gè)線程執(zhí)行類實(shí)現(xiàn)Runnable接口,在這個(gè)執(zhí)行類里實(shí)現(xiàn)Runnable的run()方法,創(chuàng)建該執(zhí)行類的對(duì)象后,用此執(zhí)行類對(duì)象初始化新線程,啟動(dòng)新線程時(shí)即執(zhí)行這個(gè)執(zhí)行對(duì)象的run()方法;
class MyRunnable implements Runnable { @Override public void run() { System.out.println("This is my thread"); } } public class Test { public static void main(String[] args) { Thread thread = new Thread(new MyRunnable()); thread.start(); } }
3.通過線程工廠用工廠模式來創(chuàng)建新線程,新建工廠類繼承ThreadFactory類重寫newThread()方法,通過指定實(shí)現(xiàn)了Runnable接口的執(zhí)行類來創(chuàng)建與之對(duì)應(yīng)的線程;
public class ThreadFactoryDemo { public static void main(String[] args) { ThreadFactory factory = new ThreadFactory() { @Override public Thread newThread(Runnable r) { // TODO Auto-generated method stub return new Thread(r); } }; factory.newThread(new Runnable() { @Override public void run() { System.out.println("in runnable."); } }).start(); } }
注意:只有調(diào)用Thread類的Start方法,才能真正地在一個(gè)獨(dú)立的線程中執(zhí)行代碼,直接調(diào)用Thread類的run方法,并不能啟動(dòng)一個(gè)新的線程,代碼是在調(diào)用者線程中執(zhí)行的。
那么主線程的run()方法在哪里呢?任何java程序的main執(zhí)行入口擔(dān)當(dāng)著啟動(dòng)主線程的作用,只要進(jìn)入了main函數(shù)就執(zhí)行了主線程,因此整個(gè)main函數(shù)里的內(nèi)容就是主線程的run()方法。
線程究竟執(zhí)行哪個(gè)run()方法
當(dāng)線程同時(shí)具有可執(zhí)行對(duì)象實(shí)現(xiàn)的run()方法和線程重寫的run()方法時(shí),啟動(dòng)線程時(shí)究竟執(zhí)行哪個(gè)run()方法呢?
結(jié)果是如果只定義了可執(zhí)行對(duì)象的run()方法則執(zhí)行這個(gè)run()方法,如果只重寫了線程的run()方法則執(zhí)行這個(gè)run()方法,如果兩個(gè)方法都有則執(zhí)行線程重寫的run()方法。
public class Test { public static void main(String[] args) { Thread thread = new Thread(new Runnable() { @Override public void run() { System.out.println("Runnable.run()"); } }) { @Override public void run() { // TODO Auto-generated method stub System.out.println("Thread.run()"); } }; thread.start(); } }
線程的休眠
使用Thread類的sleep()方法或者使用TimeUnit的相關(guān)方法來休眠線程,休眠的意思是資源仍被占用,但是線程保留原來的狀態(tài)沒有活動(dòng);
public class ThreadSleep { public static void main(String[] args) { Thread th = new Thread(new Runnable() { public void run() { for (int i = 0; i < 10; i++) { try { // Thread.sleep(500); TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } } } }); th.start(); } }
線程中斷
線程中斷的意思是線程停止當(dāng)前的運(yùn)行狀態(tài)讓出資源結(jié)束生命周期,當(dāng)外界想要一個(gè)線程中斷時(shí)需要調(diào)用它的interrupted()方法,調(diào)用后不是直接就可以中斷這個(gè)線程,而是將線程的interrupted標(biāo)記位賦為1,如果要線程要響應(yīng)這個(gè)中斷則定期需要檢查這個(gè)標(biāo)記,檢查到被中斷標(biāo)記后自己退出執(zhí)行狀態(tài)。
public class ThreadInterruptDemo { public static void main(String[] args) throws InterruptedException { Thread thread = new Thread() { @Override public void run() { while (true) { System.out.println("running"); if (isInterrupted()) return; } } }; thread.start(); Thread.sleep(2000); thread.interrupt(); } }
線程定時(shí)任務(wù)
線程要實(shí)現(xiàn)定時(shí)任務(wù)的話可以使用Runnable的實(shí)現(xiàn)類TimerTask,此類需要重寫run()方法以完成具體需要進(jìn)行的定時(shí)任務(wù)。然后由定時(shí)器Timer來調(diào)度,使用Timer的schedle()方法相當(dāng)于啟動(dòng)這個(gè)定時(shí)任務(wù)線程。
public class TimerTaskDemo { public static void main(String[] args) { TimerTask task = new TimerTask() { private int counter = 0; @Override public void run() { System.out.println(counter + ":invoked!"); counter++; } }; Timer timer = new Timer(); // 過2秒鐘后首次運(yùn)行,以后每隔3秒運(yùn)行一次 timer.schedule(task, 2000, 3000); } }
線程運(yùn)行過程中的異常處理
線程的run()方法中是不允許直接拋出異常的,也就是說不能有這樣的寫法:run() throws Exception ,原因在于在線程的運(yùn)行過程中應(yīng)該最大限度地保持正常工作,因此除了一些不可預(yù)知的運(yùn)行時(shí)異常,不應(yīng)該主動(dòng)拋出受控異常。如果非要在run()方法里處理拋出的異常,則應(yīng)該定義一個(gè)實(shí)現(xiàn)了UncaughtExceptionHandler的類,然后指定這個(gè)類的對(duì)象在重寫的uncaughtException()方法里去處理拋出的異常。另外一種方法是,將這個(gè)線程加入一個(gè)線程組,在線程組里重寫uncaughtException()方法來處理拋出的異常,這時(shí)線程組的作用相當(dāng)于實(shí)現(xiàn)了UncaughtExceptionHandler的類。
1.使用handler對(duì)象處理異常:
public class ThreadTest { public static void main(String[] args) { Thread thread = new Thread(new Runnable() { @Override public void run() { throw new RuntimeException("格式錯(cuò)誤"); } }); thread.setUncaughtExceptionHandler(new MyHandler()); thread.start(); } } class MyHandler implements UncaughtExceptionHandler { @Override public void uncaughtException(Thread t, Throwable e) { System.out.println(t.getName() + ":" + e.getMessage()); } }
2.使用線程組處理異常:
public class ThreadGroupDemo { public static void main(String[] args) { ThreadGroup threadGroup1 = new ThreadGroup("group1") { public void uncaughtException(Thread t, Throwable e) { System.out.println(t.getName() + ": " + e.getMessage()); } }; Thread thread1 = new Thread(threadGroup1, new Runnable() { public void run() { throw new RuntimeException("測(cè)試異常"); } }); thread1.start(); } }
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/64617.html
摘要:線程可以被稱為輕量級(jí)進(jìn)程。一個(gè)守護(hù)線程是在后臺(tái)執(zhí)行并且不會(huì)阻止終止的線程。其他的線程狀態(tài)還有,和。上下文切換是多任務(wù)操作系統(tǒng)和多線程環(huán)境的基本特征。在的線程中并沒有可供任何對(duì)象使用的鎖和同步器。 原文:Java Multi-Threading and Concurrency Interview Questions with Answers 翻譯:并發(fā)編程網(wǎng) - 鄭旭東 校對(duì):方騰飛 多...
摘要:多線程和并發(fā)問題是技術(shù)面試中面試官比較喜歡問的問題之一。線程可以被稱為輕量級(jí)進(jìn)程。一個(gè)守護(hù)線程是在后臺(tái)執(zhí)行并且不會(huì)阻止終止的線程。其他的線程狀態(tài)還有,和。上下文切換是多任務(wù)操作系統(tǒng)和多線程環(huán)境的基本特征。 多線程和并發(fā)問題是 Java 技術(shù)面試中面試官比較喜歡問的問題之一。在這里,從面試的角度列出了大部分重要的問題,但是你仍然應(yīng)該牢固的掌握J(rèn)ava多線程基礎(chǔ)知識(shí)來對(duì)應(yīng)日后碰到的問題。(...
摘要:超詳細(xì)的面試題總結(jié)一之基本知識(shí)多線程和虛擬機(jī)創(chuàng)建線程有幾種不同的方式你喜歡哪一種為什么繼承類實(shí)現(xiàn)接口應(yīng)用程序可以使用框架來創(chuàng)建線程池實(shí)現(xiàn)接口。死亡線程方法執(zhí)行結(jié)束,或者因異常退出了方法,則該線程結(jié)束生命周期。死亡的線程不可再次復(fù)生。 超詳細(xì)的Java面試題總結(jié)(一)之Java基本知識(shí) 多線程和Java虛擬機(jī) 創(chuàng)建線程有幾種不同的方式?你喜歡哪一種?為什么? 繼承Thread類 實(shí)現(xiàn)R...
摘要:在這個(gè)范圍廣大的并發(fā)技術(shù)領(lǐng)域當(dāng)中多線程編程可以說是基礎(chǔ)和核心,大多數(shù)抽象并發(fā)問題的構(gòu)思與解決都是基于多線程模型來進(jìn)行的。一般來說,多線程程序會(huì)面臨三類問題正確性問題效率問題死鎖問題。 多線程編程或者說范圍更大的并發(fā)編程是一種非常復(fù)雜且容易出錯(cuò)的編程方式,但是我們?yōu)槭裁催€要冒著風(fēng)險(xiǎn)艱辛地學(xué)習(xí)各種多線程編程技術(shù)、解決各種并發(fā)問題呢? 因?yàn)椴l(fā)是整個(gè)分布式集群的基礎(chǔ),通過分布式集群不僅可以大...
摘要:一線程的基本概念單線程簡(jiǎn)單的說,單線程就是進(jìn)程中只有一個(gè)線程。多線程由一個(gè)以上線程組成的程序稱為多線程程序。當(dāng)線程調(diào)用完方法進(jìn)入后會(huì)自動(dòng)釋放鎖,線程獲得鎖。 一、線程的基本概念 1.1 單線程 簡(jiǎn)單的說,單線程就是進(jìn)程中只有一個(gè)線程。單線程在程序執(zhí)行時(shí),所走的程序路徑按照連續(xù)順序排下來,前面的必須處理好,后面的才會(huì)執(zhí)行。 Java示例: public class SingleThrea...
摘要:基礎(chǔ)知識(shí)復(fù)習(xí)后端掘金的作用表示靜態(tài)修飾符,使用修飾的變量,在中分配內(nèi)存后一直存在,直到程序退出才釋放空間。將對(duì)象編碼為字節(jié)流稱之為序列化,反之將字節(jié)流重建成對(duì)象稱之為反序列化。 Java 學(xué)習(xí)過程|完整思維導(dǎo)圖 - 后端 - 掘金JVM 1. 內(nèi)存模型( 內(nèi)存分為幾部分? 堆溢出、棧溢出原因及實(shí)例?線上如何排查?) 2. 類加載機(jī)制 3. 垃圾回收 Java基礎(chǔ) 什么是接口?什么是抽象...
閱讀 958·2021-09-26 09:55
閱讀 3220·2021-09-22 15:36
閱讀 3000·2021-09-04 16:48
閱讀 3155·2021-09-01 11:41
閱讀 2608·2019-08-30 13:49
閱讀 1504·2019-08-29 18:46
閱讀 3559·2019-08-29 17:28
閱讀 3446·2019-08-29 14:11