java中Thread的深入了解(一)

線程

? ? ? ? 線程是進程中的一個單一順序的執行單元,也被稱為輕量進程(lightweight process)。線程有自己的必須資源,同時與其他線程進程共享全部資源。同一個進程中,線程是并發執行的。由于線程的之間的相互制約,線程有就緒、阻塞、運行、結束等狀態。

一 新建線程

我們先創建兩個線程類:

新建一個MyThread類 繼承 Thread來覆蓋 run方法:

MyThread類

新建MyRunnable類 實現Runnable 接口:


MyRunable類

創建以及執行兩個線程類

主線程Main
線程結果

二 驗證線程并發

在上述創建的MyThread類和MyRunnable類各自的run方法輸出上 加個for循環for(int i=0;i<10000;i++);

循環線程
輸出結果extends

如果是順序執行,應該會是 extendsThread全部輸出完 ,才輸出implement thread。但是這并不是而是出現交叉結果 證明線程是并發執行。

交叉原理就是每個代碼 在cpu時間片內執行一段時間,到時間就換一個代碼 在cpu時間片內執行,但是如果時間片內打印完了,就看不見交叉現象。

單核cpu

三 線程聲明周期(或者線程狀態)

java中線程基本上有以下圖片中的幾種狀態:

線程狀態

首先我們要做一個輸出線程狀態的類:

線程狀態

public static void printThreadState(Thread thread){

Thread.State state=thread.getState();

switch(state){

//1.新建狀態

caseNEW:

info(thread.getName()+" state is NEW");break;

//2.執行狀態

case RUNNABLE:

info(thread.getName()+" state is RUNNABLE");break;

//3.等待超時狀態

case TIMED_WAITING:

console.info(thread.getName()+" state is TIMED_WAITING");break;

//4.等待狀態

case WAITING:

info(thread.getName()+" state is WAITING");break;

//5.阻塞狀態

case BLOCKED:

info(thread.getName()+" state is BLOCKED");break;

//6.結束狀態

caseTERMINATED:

info(thread.getName()+" state is TERMINATED");break;

default:

info

(thread.getName()+" state is UNKOWN");

}

}

//打印

public static? void info(Object o){

System.out.println(String.valueOf(o));

}

1.新建狀態:

new之后 start之前都屬于NEW狀態,一旦狀態變成其他,則不會再變成NEW狀態。

public static? void main(String args[]) throws InterruptedException{

Thread t=new Thread(new Runnable() {

@Override

public void run() {

}

});

printThreadState(t);//查看new之后的thread狀態

}

2.執行狀態

在run()方法里的時候,線程處于執行狀態。一旦run()方法執行完畢,則狀態就不是執行狀態了

執行狀態
線程狀態輸出結果

3.等待超時狀態

當調用wait(long timeout)方法的時候,線程處于等待狀態,并且超時后并不馬上返回,而是等待獲取鎖后返回。

查看wait(long timeout)
輸出結果

驗證超時后并不馬上返回,而是等待獲取鎖后返回。

添加一條輸出結果
如果是wait(long timeout)方法時候,提前先把鎖獲取過來等待20s
會發現輸出結果線程還是阻塞狀態

所以我們會發現一個問題,wait的超時只是一個預想, 多少時間后我再去獲取鎖,如果拿到就返回 拿不到就處于等待狀態。這里就會發現這里等待是最少需要long timeout時間。

wait(等多少時間后 再去競爭鎖),wait的時間內 我不去競爭 跟別人搶鎖,所以這個時間 不保證鎖一定能搶回來。

注意:Thread.sleep 也會進入TIME_WAITING狀態。

5.等待狀態

wait()睡眠不參與搶鎖,等待notify來進行喚醒。

放棄搶鎖,處于waiting狀態
waiting狀態時候喚醒
輸出結果

wait 也可以通過interrupt喚醒,interrupt是中斷線程的方法。

5.阻塞狀態

如果獲取不到鎖,就一直在阻塞狀態,直到獲取鎖為止。

把循環鎖死,當狀態位鎖死的時候釋放鎖
輸出結果

6.結束狀態

在run()方法執行結束以后,線程處于結束狀態

結束狀態

但是當這個線程執行結束了之后,是否代表這個線程被銷毀了呢。然而只是線程執行單元銷毀了,但是線程對象還在。雖然這個線程對象還存在,但是它已經不能進行再次的start()方法進行執行了。

四 研究多線程鎖問題

經典并發問題:當運行一萬個線程想List插入的時候,預期結果是有10000個,但是輸出確不是10000個,而是少于1000個。原因是 線程并發執行獲取list的長度是過期的。

比如我拿到list ,你也拿到list ,咱倆同時看list里有1條數據 我把數據插入第二個位置 ,你也插入第二個位置 ,就會導致list最終結果只有2條數據,實際上插入了3條數據。

public static void ThreadMuliteTest() throws InterruptedException {

final?List?list=new?ArrayList();

for(int?i=0;i<10000;i++){

new?Thread(new?Runnable()?{

@Override

public?void?run()?{

list.add(Thread.currentThread().getName());

}

}).start();

}

Thread.sleep(1000);

System.out.println(list.size());

}

輸出結果

這就是線程并發問題,并發問題有個解決辦法 就是對線程進行枷鎖讓他排隊,我拿到了 你就不能拿。

synchronized 代碼段是java給線程的一個控制權,可以鎖住一個資源,防止被其他人用。加鎖之后線程就進入了 排隊狀態 ,只有一個線程能拿到list的權限 其他等待。

還有一種操作 就是我得到資源后 ,可以釋放一段時間給別人用 ,超時了 我在拿回來自己用。

public static void ThreadGetWait() throws InterruptedException {

Object lock=new Object();

new Thread(new Runnable() {

@Override

public void run() {

synchronized (lock){

console.info("線程一:拿到鎖");

try {

lock.wait(100);//釋放100ms

} catch (InterruptedException e) {

e.printStackTrace();

}

console.info("線程一:鎖又被我拿回來了");

try {

Thread.sleep(1000);//睡1s 鎖不給別人

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}

}).start();

Thread.sleep(10);//休眠10ms防止第二個線程拿到鎖

new Thread(new Runnable() {

@Override

public void run() {

synchronized (lock){

console.info("線程二:拿到鎖");

try {

Thread.sleep(2000);//拿到鎖后我要休眠2s

} catch (InterruptedException e) {

e.printStackTrace();

}

console.info("線程二:鎖又回來了?");

}

}

}).start();

}

輸出結果

因為線程1先運行 肯定拿到鎖,線程一暫時釋放。所以線程二緊接著拿到了鎖,線程二休眠了2s 期間并沒有釋放鎖,所以線程1一直處于阻塞狀態,線程二執行完成后 釋放鎖 線程一 打印 最后一句。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,622評論 6 544
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,716評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,746評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,991評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,706評論 6 413
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,036評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,029評論 3 450
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,203評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,725評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,451評論 3 361
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,677評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,161評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,857評論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,266評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,606評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,407評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,643評論 2 380

推薦閱讀更多精彩內容

  • 1. Java基礎部分 基礎部分的順序:基本語法,類相關的語法,內部類的語法,繼承相關的語法,異常的語法,線程的語...
    子非魚_t_閱讀 31,738評論 18 399
  • 本文主要講了java中多線程的使用方法、線程同步、線程數據傳遞、線程狀態及相應的一些線程函數用法、概述等。 首先講...
    李欣陽閱讀 2,482評論 1 15
  • Java多線程學習 [-] 一擴展javalangThread類 二實現javalangRunnable接口 三T...
    影馳閱讀 2,981評論 1 18
  • 一.synchronized方法和synchronized代碼塊 synchronized方法 只有一個線程能訪問...
    Charon_Pluto閱讀 319評論 0 0
  • 是啊,做最好自己才是成功。最好的自己是什么?什么樣的你才是最好的自己?我也不知道,只是我知道我現在的狀態不是很好。...
    我心我愿秀閱讀 227評論 0 3