Java多线程(review)
生活随笔
收集整理的這篇文章主要介紹了
Java多线程(review)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
文章目錄
- 線程狀態
- 線程方法
- 線程停止
- 線程休眠——sleep
- 網絡延時
- 模擬倒計時與打印當前系統時間
- 線程禮讓——yield
- 線程強制執行——Join
- 線程狀態
- 線程優先級
- 守護線程
- 不安全案例
- 死鎖
- Lock鎖
線程狀態
- 新建狀態:
使用 new 關鍵字和 Thread 類或其子類建立一個線程對象后,該線程對象就處于新建狀態。它保持這個狀態直到程序 start() 這個線程。 - 就緒狀態:
當線程對象調用了start()方法之后,該線程就進入就緒狀態。就緒狀態的線程處于就緒隊列中,要等待JVM里線程調度器的調度。 - 運行狀態:
如果就緒狀態的線程獲取 CPU 資源,就可以執行 run(),此時線程便處于運行狀態。處于運行狀態的線程最為復雜,它可以變為阻塞狀態、就緒狀態和死亡狀態。 - 阻塞狀態:
如果一個線程執行了sleep(睡眠)、suspend(掛起)等方法,失去所占用資源之后,該線程就從運行狀態進入阻塞狀態。在睡眠時間已到或獲得設備資源后可以重新進入就緒狀態。可以分為三種: - 等待阻塞:運行狀態中的線程執行 wait() 方法,使線程進入到等待阻塞狀態。
- 同步阻塞:線程在獲取 synchronized 同步鎖失敗(因為同步鎖被其他線程占用)。
- 其他阻塞:通過調用線程的 sleep() 或 join() 發出了 I/O 請求時,線程就會進入到阻塞狀態。當sleep() 狀態超時,join() 等待線程終止或超時,或者 I/O 處理完畢,線程重新轉入就緒狀態。
- 死亡狀態:
一個運行狀態的線程完成任務或者其他終止條件發生時,該線程就切換到終止狀態。
線程方法
| public void start() | 使該線程開始執行;Java 虛擬機調用該線程的 run 方法。 |
| public void run() | 如果該線程是使用獨立的 Runnable 運行對象構造的,則調用該 Runnable 對象的 run 方法;否則,該方法不執行任何操作并返回。 |
| public final void setName(String name) | 改變線程名稱,使之與參數 name 相同。 |
| public final void setPriority(int priority) | 更改線程的優先級。 |
| public final void setDaemon(boolean on) | 將該線程標記為守護線程或用戶線程。 |
| public final void join(long millisec) | 等待該線程終止的時間最長為 millis 毫秒。 |
| public void interrupt() | 中斷線程。 |
| public final boolean isAlive() | 測試線程是否處于活動狀態。 |
上述方法是被 Thread 對象調用的,下面表格的方法是 Thread 類的靜態方法。
| public static void yield() | 暫停當前正在執行的線程對象,并執行其他線程。 |
| public static void sleep(long millisec) | 在指定的毫秒數內讓當前正在執行的線程休眠(暫停執行),此操作受到系統計時器和調度程序精度和準確性的影響。 |
| public static boolean holdsLock(Object x) | 當且僅當當前線程在指定的對象上保持監視器鎖時,才返回 true。 |
| public static Thread currentThread() | 返回對當前正在執行的線程對象的引用。 |
| public static void dumpStack() | 將當前線程的堆棧跟蹤打印至標準錯誤流。 |
線程停止
設置一個公開的方法停止線程,轉換標志位
線程休眠——sleep
- sleep(時間)指定當前線程阻塞的毫秒數;
- sleep存在異常InterruptedException;
- sleep時間達到后線程進入就緒狀態
- sleep可以模擬網絡延時,倒計時等。
- 每個對象都有一個鎖,sleep不會釋放鎖。
網絡延時
- 模擬網絡延時:擴大線程的發生性
模擬倒計時與打印當前系統時間
package com.zeng.state;import java.text.SimpleDateFormat; import java.util.Date;//模擬倒計時 public class TestSleep02 {public static void main(String[] args) throws InterruptedException {//模擬倒計時(調用靜態方法)// tenDown();//打印當前系統時間Date startTime = new Date(System.currentTimeMillis());while(true){try {// Date startTime = new Date(System.currentTimeMillis());Thread.sleep(1000);System.out.println(new SimpleDateFormat("HH:mm:ss").format(startTime));startTime = new Date(System.currentTimeMillis());//獲取當前時間} catch (InterruptedException e) {e.printStackTrace();}}}public static /*加上static可以直接調用(靜態方法)*/void tenDown() throws InterruptedException {int num=10;while(true){Thread.sleep(1000);//sleep存在異常,拋出System.out.println(num--);if(num<=0){break;}}} }線程禮讓——yield
- 禮讓線程,讓正在執行的線程暫停,但不阻塞
- 將線程狀態轉為就緒狀態
- 讓CPU重新調度,禮讓不一定成功!
線程強制執行——Join
- Join合并線程,待此線程執行完成后,再執行其他線程,其他線程阻塞
- 可以想象成插隊
線程狀態
線程狀態。 線程可以處于以下狀態之一:
| NEW | 尚未啟動的線程處于此狀態。 |
| RUNNABLE | 在Java虛擬機中執行的線程處于此狀態。 |
| BLOCKED | 被阻塞等待監視器鎖定的線程處于此狀態。 |
| WAITING | 正在等待另一個線程執行特定動作的線程處于此狀態。 |
| TIMED_WAITING | 正在等待另一個線程執行動作達到指定等待時間的線程處于此狀態。 |
| TERMINATED | 已退出的線程處于此狀態。 |
一個線程可以在給定時間點處于一個狀態。 這些狀態是不反映任何操作系統線程狀態的虛擬機狀態。
package com.zeng.state;public class TestState {public static void main(String[] args) {Thread thread=new Thread(()->{for (int i = 0; i < 5; i++) {try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("///");});//觀察狀態Thread.State state = thread.getState();System.out.println(state);//new//觀察啟動后thread.start();//啟動線程state=thread.getState();System.out.println(state);//Runwhile(state!=Thread.State.TERMINATED){try {Thread.sleep(1000);state=thread.getState();System.out.println(state);} catch (InterruptedException e) {e.printStackTrace();}}// thread.start();線程進入死亡狀態后,就不能再啟動,直接報錯} }線程優先級
- java提供一個線程調度器來監控程序中啟動后進入就緒狀態的所有線程,線程調度器按照優先級決定應該調度哪個線程來執行。
- 線程的優先級用數字表示,范圍從1~10;
- Thread.MIN_PRIORITY=1;
- Thread.MAX_PRIORITY=10;
- Thread.NORM_PRIORITY=5;
- 使用以下方式改變或獲取優先級
- getPriority().setPriority(int XXX)
- 優先級的設定建議在start()調度前(先設置優先級,再啟動)
- 優先級低只意味著獲得調度的概率低,并不是優先級低就不會被調用了,這都是看CPU調度
守護線程
- 線程分為用戶線程和守護線程
- 虛擬機必須保護用戶線程執行完畢
- 虛擬機不必等待守護線程執行完畢
- 如,后臺記錄日志操作,監控內存,垃圾回收等待
不安全案例
package com.zeng.syn; //不安全的買票 //線程不安全,有負數public class TestUnsafeBuyTicket {public static void main(String[] args) {BuyTicket station = new BuyTicket();new Thread(station,"我emo了").start();new Thread(station,"你笑了").start();new Thread(station,"可惡的黃牛").start();} }class BuyTicket implements Runnable{//票private int ticketNums=10;boolean flag=true;//外部停止方式@Overridepublic void run() {//買票while(flag){try {buy();} catch (InterruptedException e) {e.printStackTrace();}}}//synchronized 同步方法,鎖的是thisprivate synchronized void buy() throws InterruptedException {//判斷是否有票if(ticketNums<=0){flag=false;return;}//模擬延時Thread.sleep(100);//買票System.out.println(Thread.currentThread().getName()+"拿到"+ticketNums--);} } package com.zeng.syn;import java.util.ArrayList;//線程不安全的集合 public class TestUnsafeList {public static void main(String[] args) {ArrayList<String> list = new ArrayList<>();for (int i = 0; i < 10000; i++) {new Thread(()->{synchronized (list){list.add(Thread.currentThread().getName());}}).start();}try {Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(list.size());} } package com.zeng.syn;import java.util.concurrent.CopyOnWriteArrayList; //測試JUC安全類型的集合 public class TestJUc {public static void main(String[] args) {CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();for (int i = 0; i < 1000; i++) {new Thread(()->{list.add(Thread.currentThread().getName());});}try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(list.size());} }死鎖
- 產生死鎖的四個必要條件
- 互斥條件:一個資源每次只能被一個進程使用。
- 請求與保持條件:一個進程因請求資源而阻塞時,對已獲得的資源保持不放。
- 不剝奪條件:進程已獲得的資源,在未使用完之前,不能強行剝奪。
- 循環等待條件:若干進程之間形成一種頭尾相接的循環等待資源關系。
Lock鎖
- Lock是顯式鎖(手動開啟和關閉鎖,別忘記關閉鎖)synchronized是隱式鎖,出了作用域自動釋放。
- Lock只有代碼塊鎖,synchronized有代碼塊鎖和方法鎖
- 使用Lock鎖,JVM花費較少的時間來調度線程,性能更好。并且具有更好的擴展性(提供更多的子類)
- 優先使用順序
- Lock>同步代碼塊(已經進入方法體,分配了相應資源)>同步方法(在方法體之外)
總結
以上是生活随笔為你收集整理的Java多线程(review)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 樱桃干的功效与作用、禁忌和食用方法
- 下一篇: 白石榴的功效与作用、禁忌和食用方法