其然IT教育一直秉承“用良心做教育”的理念,致力于打造IT教育全產業(yè)鏈 人才服務平臺,公司總部位于北京,目前已在深圳、上海、鄭州、廣州、大連、武漢、成都、西安、杭州、青島、重慶、長沙、哈爾濱、南京、太原成 立了分公司,年培養(yǎng)優(yōu)質人才20000余人,同期在校學員5000余人,合作院校超500所,合作企業(yè)超10000家,每年有數十萬名學員受益于千鋒互聯(lián)組織 的技術研討會、技術培訓課、網絡公開課及免費教學視頻。
其然IT歷程精彩紛呈,獲得榮譽包括:中關村移動互聯(lián)網產業(yè)聯(lián)盟副理事長 單位、中國軟件協(xié)會教育培訓委員會認證一級培訓機構、中關村國際孵化軟件協(xié)會授權中關村移動互聯(lián)網學院、教育部教育管理信息中心指定移動互聯(lián) 網實訓基地等。
其然IT教育面授課程包含HTML5大前端培訓、JavaEE 分布式開發(fā)培訓、 Python全棧 人工智能培訓、全鏈路UI/UE設計培訓、物聯(lián)網 嵌入式培訓、360網絡安全、大數據 人工智能培訓、全棧軟件測試培訓、PHP全棧 服務器 集群培訓、云計算 信息安全培訓、Unity游戲開發(fā)培訓、區(qū)塊鏈、紅帽RHCE認證,采用全程面授高品質、高成本培養(yǎng)模式,教學大綱緊跟企業(yè)需求,擁 有全國一體化就業(yè)保障服務,成為學員信賴的IT職業(yè)教育品牌。
多年Java開發(fā)從業(yè)者:首先,這個問題主要問:自學Java編程技術,如果才 能找到一份Java編程的工作。按照現(xiàn)在的招聘標準來看,無論你去哪個公司面試,你只需要滿足他們公司的需求就可以。
找到一份Java編程工作需要掌握的內容如下 :
首先是Javase作為Java**基本的學習 內容,不在多說。
然后是掌握Java的基本原理,因為做Java 編程開發(fā)必須學會Java,用到Java非常多,但是現(xiàn)在很多公司是不用去寫原生的Java,但是如果你想成為一個厲害的Java開發(fā)者,Java必須從理論到實 際操作中都要非常得心應手。
現(xiàn)在公司是必須要求會用框架的,所以取代Java的就是jQuery,這是一個非 常簡易的框架,學jQuery的時候你就會覺得它比Java好用的多。所以jQuery是你必須掌握的。
還有必須學一些框架,比如SpringMVC、Spring、Mybatis、Struts、Hibernate等等,這些就會難理解一些,但是公司是需要要求你會框架的,目前國內的公司應用SSH比 較多,建議至少學三個框架,這是找到工作的基本需求。
數據庫技術是Java工作者必須掌握的技能常用就是Mysql。
Javaweb的內容還有html、css、jsp、Servlet等技術,這些都是現(xiàn)在找Java開發(fā)必須掌握的東西。
以上就是粗略的必須掌握的技術,如果你想找到一份Java開發(fā)的工作,上述 相關技術必須熟練掌握并且應用到項目中。
JAVA 分布式大綱
一階段 java基礎,我們將學習變量,基本數據類型,進制,轉義字符,運 算符,分支語句和循環(huán)語句等,以達到訓練基礎語法和邏輯能力的目的。還有對數組、面向對象和異常處理等。
二階段 javaWeb,主要是學習Web前端開發(fā)基礎和框架、Servlet和JSP在Web 后端的應用、Web后端開發(fā)相關專題、MVC和分層架構以及項目開發(fā)流程及CASE工具的使用等。
三階段 java框架,像框架整合開發(fā)(SSH/SSS)、RESTful架構和移動端接口 設計、第三方接口和在線支付功能、網站安全和Spring Security應用實戰(zhàn)、復雜用戶交互處理和Spring Web Flow的應用、MyBatis的應用和SSM整合等 技術點都是需要你掌握的。
四階段 java 云數據,億級并發(fā)架構演進、Linux基礎、搭建tomcat環(huán)境以 及大數據開發(fā)云計算等高級Java教程,是Java技術的高端知識。其中穿插項目實戰(zhàn)演練,企業(yè)真實項目供學員應用學習,進行知識體系的“二次學習” 。
Java線程的終止——interrupt
>
取消/關閉的場景
我們知道,**線程的start方法啟動一個線程后,線程開始執(zhí)行run方法,run方法運行結束后線程退出,那為什么還需要結束一個線程呢?有多種情況,比如說: 很多線程的運行模式是死循環(huán),比如在生產者/消費者模式中,消費者主體就是一個死循環(huán),它不停的從隊列中接受任務,執(zhí)行任務,在停止程序時,我們需要一種”優(yōu)雅”的方法以關閉該線程。 在一些圖形用戶界面程序中,線程是用戶啟動的,完成一些任務,比如從遠程服務器上**一個文件,在**過程中,用戶可能會希望取消該任務。 在一些場景中,比如從第三方服務器查詢一個結果,我們希望在限定的時間內得到結果,如果得不到,我們會希望取消該任務。 有時,我們會啟動多個線程做同一件事,比如類似搶火車票,我們可能會讓多個好友幫忙從多個渠道買火車票,只要有一個渠道買到了,我們會通知取消其他渠道。
取消/關閉的機制 java的Thread類定義了如下方法: public final void stop()
這個方法看上去就可以停止線程,但這個方法被標記為了過時,簡單的說,我們不應該使用它,可以忽略它。
在Java中,停止一個線程的主要機制是中斷,中斷并不是強迫終止一個線程,它是一種協(xié)作機制,是給線程傳遞一個取消信號,但是由線程來決定如何以及何時退出,本節(jié)我們主要就是來理解Java的中斷機制。
Thread類定義了如下關于中斷的方法: public boolean isInterrupted() public void interrupt() public static boolean interrupted()
這三個方法名字類似,比較容易混淆,我們解釋一下。isInterrupted()和interrupt()是實例方法,調用它們需要**線程對象,interrupted()是靜態(tài)方法,實際會調用Thread.currentThread()操作當前線程。
每個線程都有一個標志位,表示該線程是否被中斷了。 isInterrupted:就是返回對應線程的中斷標志位是否為true。 interrupted:返回當前線程的中斷標志位是否為true,但它還有一個重要的副作用,就是清空中斷標志位,也就是說,連續(xù)兩次調用interrupted(),**次返回的結果為true,第二次一般就是false (除非同時又發(fā)生了一次中斷)。 interrupt:表示中斷對應的線程,中斷具體意味著什么呢?下面我們進一步來說明。
線程對中斷的反應 interrupt()對線程的影響與線程的狀態(tài)和在進行的IO操作有關,我們先主要考慮線程的狀態(tài): RUNNABLE:線程在運行或具備運行條件只是在等待操作系統(tǒng)調度 WAITING/TIMED_WAITING:線程在等待某個條件或超時 BLOCKED:線程在等待鎖,試圖進入同步塊 NEW/TERMINATED:線程還未啟動或已結束
RUNNABLE 如果線程在運行中,且沒有執(zhí)行IO操作,interrupt()只是會設置線程的中斷標志位,沒有任何其它作用。線程應該在運行過程中合適的位置檢查中斷標志位,比如說,如果主體代碼是一個循環(huán),可以在循環(huán)開始處進行檢查,如下所示:
public class InterruptRunnableDemo extends Thread { @Override public void run() { while (!Thread.currentThread().isInterrupted()) { // ... 單次循環(huán)代碼 } System.out.PRintln("done "); } public static void main(String[] args) throws InterruptedException { Thread thread = new InterruptRunnableDemo(); thread.start(); Thread.sleep(1000); thread.interrupt(); } }WAITING/TIMED_WAITING 線程執(zhí)行如下方法會進入WAITING狀態(tài): public final void join() throws InterruptedException public final void wait() throws InterruptedException
執(zhí)行如下方法會進入TIMED_WAITING狀態(tài): public final native void wait(long timeout) throws InterruptedException; public static native void sleep(long millis) throws InterruptedException; public final synchronized void join(long millis) throws InterruptedException
在這些狀態(tài)時,對線程對象調用interrupt()會使得該線程拋出InterruptedException,需要注意的是,拋出異常后,中斷標志位會被清空,而不是被設置。比如說,執(zhí)行如下代碼:
Thread t = new Thread (){ @Override public void run() { try { Thread.sleep(1000); } catch (InterruptedException e) { System.out.println(isInterrupted()); } } }; t.start(); try { Thread.sleep(100); } catch (InterruptedException e) { } t.interrupt();程序的輸出為false。
InterruptedException是一個受檢異常,線程必須進行處理。我們在異常處理中介紹過,處理異常的基本思路是,如果你知道怎么處理,就進行處理,如果不知道,就應該向上傳遞,通常情況下,你不應該做的是,捕獲異常然后忽略。
捕獲到InterruptedException,通常表示希望結束該線程,線程大概有兩種處理方式: 向上傳遞該異常,這使得該方法也變成了一個可中斷的方法,需要調用者進行處理。 有些情況,不能向上傳遞異常,比如Thread的run方法,它的聲明是固定的,不能拋出任何受檢異常,這時,應該捕獲異常,進行合適的清理操作,清理后,一般應該調用Thread的interrupt方法設置中斷標志位,使得其他代碼有辦法知道它發(fā)生了中斷。
**種方式的示例代碼如下:
public void interruptibleMethod() throws InterruptedException{ // ... 包含wait, join 或 sleep 方法 Thread.sleep(1000); }第二種方式的示例代碼如下:
public class InterruptWaitingDemo extends Thread { @Override public void run() { while (!Thread.currentThread().isInterrupted()) { try { // 模擬任務代碼 Thread.sleep(2000); } catch (InterruptedException e) { // ... 清理操作 // 重設中斷標志位 Thread.currentThread().interrupt(); } } System.out.println(isInterrupted()); } public static void main(String[] args) { InterruptWaitingDemo thread = new InterruptWaitingDemo(); thread.start(); try { Thread.sleep(100); } catch (InterruptedException e) { } thread.interrupt(); } }BLOCKED 如果線程在等待鎖,對線程對象調用interrupt()只是會設置線程的中斷標志位,線程依然會處于BLOCKED狀態(tài),也就是說,interrupt()并不能使一個在等待鎖的線程真正”中斷”。我們看段代碼:
public class InterruptSynchronizedDemo { private static Object lock = new Object(); private static class A extends Thread { @Override public void run() { synchronized (lock) { while (!Thread.currentThread().isInterrupted()) { } } System.out.println("exit"); } } public static void test() throws InterruptedException { synchronized (lock) { A a = new A(); a.start(); Thread.sleep(1000); a.interrupt(); a.join(); } } public static void main(String[] args) throws InterruptedException { test(); } }test方法在持有鎖lock的情況下啟動線程a,而線程a也去嘗試獲得鎖lock,所以會進入鎖等待隊列,隨后test調用線程a的interrupt方法并等待線程線程a結束,線程a會結束嗎?不會,interrupt方法只會設置線程的中斷標志,而并不會使它從鎖等待隊列中出來。
我們稍微修改下代碼,去掉test方法中的**后一行a.join,即變?yōu)椋?
public static void test() throws InterruptedException { synchronized (lock) { A a = new A(); a.start(); Thread.sleep(1000); a.interrupt(); } }這時,程序就會退出。為什么呢?因為主線程不再等待線程a結束,釋放鎖lock后,線程a會獲得鎖,然后檢測到發(fā)生了中斷,所以會退出。
在使用synchronized關鍵字獲取鎖的過程中不響應中斷請求,這是synchronized的局限性。如果這對程序是一個問題,應該使用顯式鎖,后面章節(jié)我們會介紹顯式鎖Lock接口,它支持以響應中斷的方式獲取鎖。
NEW/TERMINATE 如果線程尚未啟動(NEW),或者已經結束(TERMINATED),則調用interrupt()對它沒有任何效果,中斷標志位也不會被設置。比如說,以下代碼的輸出都是false。
public class InterruptNotAliveDemo { private static class A extends Thread { @Override public void run() { } } public static void test() throws InterruptedException { A a = new A(); a.interrupt(); System.out.println(a.isInterrupted()); a.start(); Thread.sleep(100); a.interrupt(); System.out.println(a.isInterrupted()); } public static void main(String[] args) throws InterruptedException { test(); } }IO操作 如果線程在等待IO操作,尤其是網絡IO,則會有一些特殊的處理,我們沒有介紹過網絡,這里只是簡單介紹下。 如果IO通道是可中斷的,即實現(xiàn)了InterruptibleChannel接口,則線程的中斷標志位會被設置,同時,線程會收到異常ClosedByInterruptException。 如果線程阻塞于Selector調用,則線程的中斷標志位會被設置,同時,阻塞的調用會立即返回。
我們重點介紹另一種情況,InputStream的read調用,該操作是不可中斷的,如果流中沒有數據,read會阻塞 (但線程狀態(tài)依然是RUNNABLE),且不響應interrupt(),與synchronized類似,調用interrupt()只會設置線程的中斷標志,而不會真正”中斷”它,我們看段代碼。
public class InterruptReadDemo { private static class A extends Thread { @Override public void run() { while(!Thread.currentThread().isInterrupted()){ try { System.out.println(System.in.read()); } catch (IOException e) { e.printStackTrace(); } } System.out.println("exit"); } } public static void main(String[] args) throws InterruptedException { A t = new A(); t.start(); Thread.sleep(100); t.interrupt(); } }線程t啟動后調用System.in.read()從標準輸入讀入一個字符,不要輸入任何字符,我們會看到,調用interrupt()不會中斷read(),線程會一直運行。
不過,有一個辦法可以中斷read()調用,那就是調用流的close方法,我們將代碼改為:
public class InterruptReadDemo { private static class A extends Thread { @Override public void run() { while (!Thread.currentThread().isInterrupted()) { try { System.out.println(System.in.read()); } catch (IOException e) { e.printStackTrace(); } } System.out.println("exit"); } public void cancel() { try { System.in.close(); } catch (IOException e) { } interrupt(); } } public static void main(String[] args) throws InterruptedException { A t = new A(); t.start(); Thread.sleep(100); t.cancel(); } }我們給線程定義了一個cancel方法,在該方法中,調用了流的close方法,同時調用了interrupt方法,這次,程序會輸出:
-1 exit也就是說,調用close方法后,read方法會返回,返回值為-1,表示流結束。
如何正確地取消/關閉線程
有三種方法可以使終止線程。
1. 使用退出標志,使線程正常退出,也就是當run方法完成后線程終止。 2. 使用stop方法強行終止線程(這個方法不推薦使用,因為stop和suspend、resume一樣,也可能發(fā)生不可預料的結果)。 3. 使用interrupt方法中斷線程。以上,我們可以看出,interrupt方法不一定會真正”中斷”線程,它只是一種協(xié)作機制,如果不明白線程在做什么,不應該貿然的調用線程的interrupt方法,以為這樣就能取消線程。
對于以線程提供服務的程序模塊而言,它應該封裝取消/關閉操作,提供單獨的取消/關閉方法給調用者,類似于InterruptReadDemo中演示的cancel方法,外部調用者應該調用這些方法而不是直接調用interrupt。
Java并發(fā)庫的一些代碼就提供了單獨的取消/關閉方法,比如說,F(xiàn)uture接口提供了如下方法以取消任務: boolean cancel(boolean mayInterruptIfRunning);
再比如,ExecutorService提供了如下兩個關閉方法: void shutdown(); List shutdownNow();
Future和ExecutorService的API文檔對這些方法都進行了詳細說明,這是我們應該學習的方式。關于這兩個接口,我們后續(xù)章節(jié)介紹。
小結 本節(jié)主要介紹了在Java中如何取消/關閉線程,主要依賴的技術是中斷,但它是一種協(xié)作機制,不會強迫終止線程,我們介紹了線程在不同狀態(tài)和IO操作時對中斷的反應,作為線程的實現(xiàn)者,應該提供明確的取消/關閉方法,并用文檔描述清楚其行為,作為線程的調用者,應該使用其取消/關閉方法,而不是貿然調用interrupt。
相關推薦:
體驗課預約試聽
倒計時
課程熱線:
客服在線時間:早上9點~下午6點,其他時間請在線預約報名或留言,謝謝!