Android入門教程 | 多執行緒
作業系統可以在同一時刻執行多個程式。例如一邊播放音樂,一邊下載檔案和瀏覽網頁。作業系統將cpu的時間片分配給每一個程式,給人一種並行處理的感覺。
一個多執行緒程式可以同時執行多個任務。通常,每一個任務稱為一個執行緒(thread),它是執行緒控制的簡稱。可以同時執行一個以上執行緒的程式成為多執行緒程式(multithreaded)。
多程式和多執行緒有哪些區別呢?
本質區別在於程式每個程式有自己的一整套變數,而執行緒則共享資料。 執行緒比程式更輕量級,建立、銷燬一個執行緒比啟動新程式的開銷要小。
實際應用中,多執行緒非常有用。例如應用一邊處理使用者的輸入指令,一遍聯網獲取資料。
Thread
Thread類屬於
java.lang
包。
要建立一個執行緒很簡單,新建一個
Thread物件,並傳入一個
Runnable,實現
run()
方法。 呼叫
start()
方法啟動執行緒。
Java
Thread t1 = new Thread(new Runnable() { @Override public void run() { System.out.println("rustfisher said: hello"); } }); t1.start();
Java lambda
Thread t1 = new Thread(() -> System.out.println("rustfisher said: hello"));t1.start();
不要直接呼叫run()方法
直接呼叫run()
方法不會啟動新的執行緒,而是直接在當前執行緒執行任務。
我們來看一個使用了
Thread.sleep()
方法的例子。
Thread t1 = new Thread(() -> { for (String a : "rustfisher said: hello".split("")) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.print(a); } });t1.start();
sleep(int)
方法會讓執行緒睡眠一個指定的時間(單位毫秒)。並且需要 try-catch 捕獲
InterruptedException
異常。
中斷執行緒
當
run()
方法執行完最後一條語句後,或者
return
,或者出現了未捕獲的異常,執行緒將會終止。
使用Thread的
interrupt
方法也可以終止執行緒。呼叫
interrupt
方法時,會修改執行緒的中斷狀態為
true
。 用
isInterrupted()
可以檢視執行緒的中斷狀態。
但如果執行緒被阻塞了,就沒法檢測中斷狀態。當在一個被阻塞的執行緒(sleep或者wait)上呼叫
interrupt
方法,阻塞呼叫將會被
InterruptedException
中斷。
被中斷的執行緒可以決定如何響應中斷。可以簡單地將中斷作為一個終止請求。比如我們主動捕獲
InterruptedException
。
Thread t2 = new Thread(() -> { for (String a : "rustfisher said: hello".split("")) { try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); System.out.println("被中斷 退出執行緒"); return; } System.out.print(a); } });t2.start();new Thread(() -> { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } t2.interrupt(); }).start();
上面這個小例子展示了用
interrupt()
來中斷執行緒
t2
。而執行緒
t2
的
run()
方法中捕獲
InterruptedException
後,可以進行自己的處理。
執行緒的狀態
執行緒有 6 種狀態,用列舉類 State 來表示:
- NEW(新建立)
- RUNNABLE(可執行)
- BLOCKED(被阻塞)
- WAITING(等待)
- TIMED_WAITING(計時等待)
- TERMINATED(被終止)
用
getState()
方法可以獲取到執行緒的狀態。
新建立執行緒
new一個執行緒的時候,執行緒還沒開始執行,此時是NEW(新建立)狀態。線上程可以執行前,還有一些工作要做。
可執行執行緒
一旦呼叫
start()
方法,執行緒處於RUNNABLE(可執行)狀態。呼叫
start()
後並不保證執行緒會立刻執行,而是要看作業系統的安排。
一個執行緒開始執行後,它不一定時刻處於執行狀態。作業系統可以讓其他執行緒獲得執行機會。一個可執行的執行緒可能正在執行也可能沒在執行。
被阻塞和等待
執行緒處於被阻塞和等待狀態時,它暫時不活動。不執行程式碼,且只消耗最少的資源。直到執行緒排程器重新啟用它。
- 一個執行緒試圖獲取一個內部的物件鎖,而該鎖被其他執行緒持有,則這個執行緒進入阻塞狀態。當這個鎖被釋放,並且執行緒排程器允許這個執行緒持有它,該執行緒變成非阻塞狀態。
- 當執行緒等待另一個執行緒通知排程器,它自己進入等待狀態。例如呼叫
Object.wait()
或者Thread.join()
方法。 - 帶有超時引數的方法可讓執行緒進入超時等待狀態。例如
Thread.sleep()
,Object.wait(long)
,Thread.join(long)
,Lock.tryLock(long time, TimeUnit unit)
被終止
終止的原因:
- run方法正常退出
- 出現了沒有捕獲的異常而終止了run方法
執行緒屬性
執行緒優先順序,守護執行緒,執行緒組以及處理未捕獲異常的處理器。
執行緒優先順序
Java中每個執行緒都有一個優先順序。預設情況下,執行緒繼承它的父執行緒的優先順序。 可用
setPriority(int)
方法設定優先順序。優先順序最大為
MAX_PRIORITY = 10
,最小為
MIN_PRIORITY = 1
,普通的是
NORM_PRIORITY = 5
。 執行緒排程器有機會選新執行緒是,會優先選高優先順序的執行緒。
守護執行緒
呼叫
setDaemon(true)
可以切換為守護執行緒(daemon thread)。守護執行緒的用途是為其他執行緒提供服務。例如計時執行緒。 當只剩下守護執行緒時,虛擬機器就退出了。
守護執行緒不應該去訪問固有資源,如檔案和資料庫。
未捕獲異常處理器
run()
方法裡丟擲一個未捕獲異常,線上程死亡前,異常被傳遞到一個用於未捕獲異常的處理器。 要使用這個處理器,需要實現介面
Thread.UncaughtExceptionHandler
,並且用
setUncaughtExceptionHandler(Thread.UncaughtExceptionHandler)
方法把它交給執行緒。
Thread t3 = new Thread(() -> { try { Thread.sleep(5); } catch (InterruptedException e) { e.printStackTrace(); return; } int x = 0, y = 3; int z = y / x; // 故意弄一個異常}); t3.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() { @Override public void uncaughtException(Thread t, Throwable e) { System.out.println(t + "有未捕獲異常"); e.printStackTrace(); } }); t3.start();
執行後,
run()
方法裡丟擲
ArithmeticException
異常
Thread[Thread-0,5,main]有未捕獲異常 java.lang.ArithmeticException: / by zero at Main.lambda$main$0(Main.java:15) at java.lang.Thread.run(Thread.java:748)
也可以用靜態方法
Thread.setDefaultUncaughtExceptionHandler(Thread.UncaughtExceptionHandler)
給所有的執行緒安裝一個預設處理器。可以在這個預設處理器裡做一些工作,例如記錄日誌。
ThreadGroup 代表著一組執行緒。也可以包含另外的執行緒組。
ThreadGroup 類實現了 UncaughtExceptionHandler 介面。它的
uncaughtException(Thread t, Throwable e)
方法會有如下操作
- 如果該執行緒組有父執行緒組,則父執行緒組的
uncaughtException
被呼叫。 - 否則,如果
Thread.getDefaultUncaughtExceptionHandler()
返回一個非空處理器,則使用這個處理器。 - 否則,如果丟擲的 Throwable是 ThreadDeath物件,就什麼也不做。
- 否則,執行緒的名字和
Throwable的棧蹤跡輸出到
System.err
上。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70008155/viewspace-2842990/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Java入門教程十三(多執行緒)Java執行緒
- c++11 多執行緒入門教程(一)C++執行緒
- Java多執行緒(一)多執行緒入門篇Java執行緒
- Java多執行緒入門Java執行緒
- 多執行緒與高併發(一)多執行緒入門執行緒
- Java多執行緒學習(一)Java多執行緒入門Java執行緒
- 多執行緒基礎入門執行緒
- python 多執行緒 入門Python執行緒
- 入門python多執行緒/多程式Python執行緒
- day20_多執行緒入門丶執行緒安全執行緒
- Linux程式多執行緒入門Linux執行緒
- go語言多執行緒入門筆記-執行緒同步Go執行緒筆記
- 【C++11多執行緒入門教程】系列之互斥量mutexC++執行緒Mutex
- Java多執行緒傻瓜入門介紹Java執行緒
- Java 高階 --- 多執行緒快速入門Java執行緒
- java多執行緒的入門小記Java執行緒
- Java入門系列-21-多執行緒Java執行緒
- iOS多執行緒程式設計入門iOS執行緒程式設計
- Android多執行緒之執行緒池Android執行緒
- JavaSE_多執行緒入門 執行緒安全 死鎖 狀態 通訊 執行緒池Java執行緒
- QT從入門到入土(四)——多執行緒QT執行緒
- c++11多執行緒入門例項C++執行緒
- vc入門寶典六(多執行緒) (轉)執行緒
- Java多執行緒程式設計入門(轉)Java執行緒程式設計
- python爬蟲入門八:多程式/多執行緒Python爬蟲執行緒
- Android《多執行緒-中》Android執行緒
- Java多執行緒 -- wait() 和 notify() 使用入門Java執行緒AI
- Java多執行緒系列——從菜鳥到入門Java執行緒
- J2me多執行緒(入門級別)執行緒
- Android多執行緒之IntentServiceAndroid執行緒Intent
- Android多執行緒總結Android執行緒
- Android中的多程式、多執行緒Android執行緒
- 多執行緒和多執行緒同步執行緒
- 多執行緒【執行緒池】執行緒
- 多執行緒--執行緒管理執行緒
- Java多執行緒——執行緒Java執行緒
- 執行緒與多執行緒執行緒
- 敲開阿里大門的執行緒、多執行緒和執行緒池面試專題阿里執行緒面試