微吼云上線多路互動直播服務 加速多場景互動直播落地
622
2025-03-31
操作系統可以在同一時刻運行多個程序。例如一邊播放音樂,一邊下載文件和瀏覽網頁。操作系統將cpu的時間片分配給每一個進程,給人一種并行處理的感覺。
一個多線程程序可以同時執行多個任務。通常,每一個任務稱為一個線程(thread),它是線程控制的簡稱。可以同時運行一個以上線程的程序成為多線程程序(multithreaded)。
多進程和多線程有哪些區別呢?
本質區別在于進程每個進程有自己的一整套變量,而線程則共享數據。
線程比進程更輕量級,創建、銷毀一個線程比啟動新進程的開銷要小。
實際應用中,多線程非常有用。例如應用一邊處理用戶的輸入指令,一遍聯網獲取數據。
本文我們介紹Java中的Thread類。
Thread
Thread類屬于java.lang包。
要創建一個線程很簡單,新建一個Thread對象,并傳入一個Runnable,實現run()方法。
調用start()方法啟動線程。
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上。
參考書籍: Core Java, Volume II - Advanced Features 7th Edition
建議參考: Concurrent Programming in Java
Java 多線程
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。