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