淺談java多線程的生命周期和同步通信多線程的生命周期和同步通信
關于上一篇的多線程-線程的創建和使用漏掉了一部分,這里補充說明一下
Thread類的有關方法(具體查看API)
void start(): 啟動線程,并執行對象的run()方法
run(): 線程在被調度時執行的操作
String getName(): 返回線程的名稱
void setName(String name):設置該線程名稱
static Thread currentThread(): 返回當前線程。在Thread子類中就是this,通常用于主線程和Runnable實現類
static void yield():線程讓步? 暫停當前正在執行的線程,把執行機會讓給優先級相同或更高的線程? 若隊列中沒有同優先級的線程,忽略此方法
join() :當某個程序執行流中調用其他線程的 join() 方法時,調用線程將被阻塞,直到 join() 方法加入的 join 線程執行完為止? 低優先級的線程也可以獲得執行
static void sleep(long millis):(指定時間:毫秒)? 令當前活動線程在指定時間段內放棄對CPU控制,使其他線程有機會被執行,時間到后重排隊。? 拋出InterruptedException異常
stop(): 強制線程生命期結束,不推薦使用
boolean isAlive():返回boolean,判斷線程是否還活著
線程調度
接著來說說線程調度,線程有兩種調度模型
分時調度模型:所有線程輪流使用 CPU 的使用權,平均分配每個線程占用 CPU 的時間片
搶占式調度模型:優先讓優先級高的線程使用 CPU,如果線程的優先級相同,那么會隨機選擇一個,優先級高的線程
獲取的 CPU 時間片相對多一些 Java使用的是搶占式調度模型
假如計算機只有一個 CPU,那么 CPU 在某一個時刻只能執行一條指令,線程只有得到CPU時間片,也就是使用權, 才可以執行指令。所以說多線程程序的執行是有隨機性,因為誰搶到CPU的使用權是不一定的
Thread類中設置和獲取線程優先級的方法
public final int getPriority():返回此線程的優先級
public final void setPriority(int newPriority):更改此線程的優先級
線程默認優先級是5;線程優先級的范圍是:1-10
線程優先級高僅僅表示線程獲取的CPU時間片的幾率高,但是要在次數比較多,或者多次運行的時候才能看到你想要的效果
言歸正傳,下面來說說本篇的重點,線程的生命周期
線程生命周期
JDK中用Thread.State類定義了線程的幾種狀態 要想實現多線程,必須在主線程中創建新的線程對象。Java語言使用Thread類及其子類的對象來表示線程,在它的一個完整的生命周期中通常要經歷如下的五種狀態:
新建: 當一個Thread類或其子類的對象被聲明并創建時,新生的線程對象處于新建狀態。
就緒:處于新建狀態的線程被start()后,將進入線程隊列等待CPU時間片,此時它已具備了運行的條件,只是沒分配到CPU資源 。
運行:當就緒的線程被調度并獲得CPU資源時,便進入運行狀態, run()方法定義了線程的操作和功能 。
阻塞:在某種特殊情況下,被人為掛起或執行輸入輸出操作時,讓出 CPU 并臨時中止自己的執行,進入阻塞狀態 。
死亡:線程完成了它的全部工作或線程被提前強制性地中止或出現異常導致結束。
用一張圖簡易表示一下:
這就是經典的線程五態轉換,接著繼續說一下線程的同步思想
線程的同步思想
問題的提出
多個線程執行的不確定性引起執行結果的不穩定。
多個線程對數據的共享,會造成操作的不完整性,會破壞數據。
例如:火車站售票程序,開啟三個窗口售票,售10張票。
class Ticket implements Runnable { private int ticket = 10; public void run() { while (true) { try { Thread.sleep(10);//休息一段時間,讓該線程沒有執行完 if (ticket > 0) { System.out.println(Thread.currentThread().getName() + "售出車票,ticket號:" + ticket--); } else break; } catch (InterruptedException e) { e.printStackTrace(); } } }}
public class ThreadSync { public static void main(String[] args) { Ticket ticket = new Ticket(); Thread thread1 = new Thread(ticket,"1窗口"); Thread thread2 = new Thread(ticket,"2窗口"); Thread thread3 = new Thread(ticket,"3窗口"); thread1.start(); thread2.start(); thread3.start(); } }
上面的代碼會出現,三個線程同時買一張票的問題,會造成操作的不完整性,會破壞數據。
為什么出現問題?這也是我們判斷多線程程序是否會有數據安全問題的標準
是否是多線程環境
是否有共享數據
是否有多條語句操作共享數據
如何解決多線程安全問題呢?
基本思想:讓程序沒有安全問題的環境 怎么實現呢? 把操作共享數據的代碼給鎖起來,讓任意時刻只能有一個線程執行即可 Java提供了同步代碼塊的方式來解決
同步代碼塊
鎖操作共享數據多條語句,可以使用同步代碼塊實現
格式: ? ? ? ?synchronized(任意對象) {? ? ? ? ? ? ? ? ?多條語句操作共享數據的代碼? ? ? ? ?}
synchroized(任意對象):就相當于給代碼加鎖了,任意對象就可以看成是一把鎖 同步的好處和弊端
好處:解決了多線程的數據安全問題
弊端:當線程很多時,因為每個線程都會去判斷同步上的鎖,這是很耗費資源的,無形中會降低程序的運行效率
同步方法
同步方法:就是把synchronized關鍵字加到方法上
格式: ? ? ? ?修飾符 synchronized 返回值類型 方法名(方法參數) { ? ?}
同步方法的鎖對象是什么呢?
this
同步靜態方法:就是把synchronized關鍵字加到靜態方法上
格式: ? ? ? ?修飾符 static synchronized 返回值類型 方法名(方法參數) { ? ?}
同步靜態方法的鎖對象是什么呢?
類名.class
Lock(鎖)
從JDK 5.0開始,Java提供了更強大的線程同步機制——通過顯式定義同步鎖對象來實現同步。同步鎖使用Lock對象充當。
java.util.concurrent.locks.Lock接口是控制多個線程對共享資源進行訪問的 工具。鎖提供了對共享資源的獨占訪問,每次只能有一個線程對Lock對象 加鎖,線程開始訪問共享資源之前應先獲得Lock對象。
ReentrantLock 類實現了Lock ,它擁有與 synchronized 相同的并發性和內存語義,在實現線程安全的控制中,比較常用的是ReentrantLock,可以顯式加鎖、釋放鎖。
例如:
class A{ private final ReentrantLock lock = new ReentrantLock(); public void method() { lock.lock(); try { // 保證線程安全的代碼; } catch (Exception e) { e.printStackTrace(); }finally { lock.unlock(); } } }}
注意:如果同步代碼有異常,要將unlock()寫入finally語句塊
synchronized 與 Lock 的對比
Lock是顯式鎖(手動開啟和關閉鎖,別忘記關閉鎖),synchronized是隱式鎖,出了作用域自動釋放 。
Lock只有代碼塊鎖,synchronized有代碼塊鎖和方法鎖 。
使用Lock鎖,JVM將花費較少的時間來調度線程,性能更好。并且具有更好的擴展性(提供更多的子類)
優先使用順序: ?Lock —>同步代碼塊(已經進入了方法體,分配了相應資源)—>同步方法 (在方法體之外)
最后提一下經典的生產者消費者模式
生產者消費者模式-多線程通信
生產者消費者模式是一個十分經典的多線程協作的模式,弄懂生產者消費者問題能夠讓我們對多線程編程的理解更加深刻,所謂生產者消費者問題,實際上主要是包含了兩類線程:
一類是生產者線程用于生產數據
一類是消費者線程用于消費數據
為了解生產者和消費者的關系,通常會采用共享的數據區域,就像是一個倉庫
生產者生產數據之后直接放置在共享數據區中,并不需要關心消費者的行為
消費者只需要從共享數據區中去獲取數據,并不需要關心生產者的行為
生產者消費者模式概述
為了體現生產和消費過程中的等待和喚醒,Java就提供了幾個方法供我們使用,這幾個方法在Object類中Object類的等待和喚醒方法:
注意: 這三個方法只有在synchronized方法或synchronized代碼塊中才能使用,否則會報 java.lang.IllegalMonitorStateException異常。? 因為這三個方法必須有鎖對象調用,而任意對象都可以作為synchronized的同步鎖, 因此這三個方法只能在Object類中聲明
好了,關于此次JAVA多線程的生命周期和同步通信就說到這里了,如有不足之處,歡迎指正!
感恩能與大家在華為云遇見!希望能與大家一起在華為云社區共同成長。
Java 任務調度 多線程
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。