在上週去面試的時候,面試官問了我乙個關於執行緒池的問題,當時沒有答上來。所以,回來了之後決定重新學習一下多執行緒。
這也是本人第一次寫部落格,之前一直想寫,但是,一直沒有搞清楚的部落格系統是怎麼玩的。這次,到網上看到了一些關於的小技巧,正好最近在學習多執行緒,拿來練練手。
1public
class
demo ;
8}.start();910
//方法二:實現runnable介面
11 runnable r = new
runnable()
16};
17new
thread(r).start();
1819
/**20
* runnable的作用,實現多執行緒。我們可以定義乙個類a實現runnable介面;然後,通過new thread(new a())等方式新建執行緒。
21* thread 是乙個類。thread本身就實現了runnable介面。我們知道「乙個類只能有乙個父類,但是卻能實現多個介面」,因此runnable具有更好的擴充套件性。使用runnable介面可以實現**重用。
22*/23}
24 }
thread類run方法原始碼:
publicvoid
run()
}
當呼叫start()方法時,執行緒最終會呼叫thread的run(),當我們繼承thread類複寫run(),執行緒會呼叫run()方法裡的**。
而在thread的run()方法,如果target不為null,就執行target.run(),不用說這裡target就是runnable物件。
執行緒的5種狀態:
新建狀態(new):執行緒物件被建立後,就進入了新建狀態。
就緒狀態(runnable):可執行狀態,隨時可能被cpu排程執行。當呼叫thread的start()方法後執行緒進入就緒狀態。
執行狀態(running):執行緒被cpu排程執行。執行緒只能從就緒狀態進入執行狀態。
阻塞狀態(blocked):執行緒因為某種原因放棄cpu使用權,暫時停止執行。知道執行緒再次進入就緒狀態,才能被cpu排程執行。
-等待阻塞:通過呼叫執行緒的wait()方法,讓執行緒等待某工作的完成。
-執行緒在獲取synchronized同步鎖失敗(因為鎖被其它執行緒所占用),它會進入同步阻塞狀態。
-其它阻塞。
死亡狀態(dead):執行緒執行完了或者因異常退出了run()方法,該執行緒結束生命週期。
這5種狀態涉及到的內容包括object類, thread和synchronized關鍵字。
object類,定義了wait(), notify(), notifyall()等休眠/喚醒方法。
thread類,定義了一些列的執行緒操作方法。例如,sleep()休眠方法, interrupt()中斷方法, getname()獲取執行緒名稱等。
synchronized,是關鍵字;它區分為synchronized**塊和synchronized方法。synchronized的作用是讓執行緒獲取物件的同步鎖。
1public
class
demo2 78
public
static
void
main(string args)
15};
16/**
17* 當少量執行緒同時訪問getnext()方法時,程式不會有什麼問題。
18* 但是如果併發量較大(這裡模擬500個執行緒同時訪問),得到結果往往不是想要的結果。
19*/
20for(int i = 0 ;i <500;i++)23}
2425 }
出現問題的原因是:value++不是乙個原子操作,或者說該操作不具備原子性。
原子性:原子是世界上最小的單位,具有不可分割性。在我們程式設計的世界裡,某個操作如果不可分割我們就稱之為該操作具有原子性。i=0不可能再分割,所以該操作具有原子性。但是getnext()方法的value++,是可以分割的,這實際上有個「讀取-修改-寫入」的操作序列。如果乙個操作具有原子性,那也就不會有執行緒安全問題。做完了就做完了!但是乙個操作不具有原子性,那麼,在這個操作在執行的過程中,有可能被外部所改變。
解析:這個類有乙個欄位value,並且提供了可改變欄位的方法,所以該物件的狀態是可變的。上面程式多個執行緒同時訪問getnext()方法時。如果執行緒是按順序執行,正確的執行方式是第一條執行緒讀取value的值並列印出來,然後對齊值進行自增操作。然後下一條執行緒再讀取value值,接著列印、自增...,結果值應該是 1、2、3、4、5...500 按順序列印出來,我們希望的結果也是這樣。但是,多執行緒之間的操作是交替執行的,當第乙個執行緒讀取value值時,第二個執行緒也有可能在做讀取value值的操作,第三個也可能做著同樣的操作。這樣,各個執行緒之間得到的值就有可能相同,而不是理想中按照順序對value的值進行遞增。
解決辦法:在run方法上加synchronized(當然也可以在getnext方法上加,只是鎖物件不一樣而已)
1public
class
demo2 78
public
static
void
main(string args)
15};
16/**
17* 當少量執行緒同時訪問getnext()方法時,程式不會有什麼問題。
18* 但是如果併發量較大(這裡模擬500個執行緒同時訪問),得到結果往往不是想要的結果。
19*/
20for(int i = 0 ;i <500;i++)23}
2425 }
thread 和 runnable 的相同點:都是「多執行緒的實現方式」。
thread 和 runnable 的不同點:
thread 是類,而runnable是介面;thread本身是實現了runnable介面的類。我們知道「乙個類只能有乙個父類,但是卻能實現多個介面」,因此runnable具有更好的擴充套件性。
此外,runnable還可以用於「資源的共享」。即,多個執行緒都是基於某乙個runnable物件建立的,它們會共享runnable物件上的資源。
通常,建議通過「runnable」實現多執行緒!
多執行緒,高併發初步(一 執行緒的建立方式)
常見的兩種執行緒建立方式 繼承thread類和實現runnable介面 具體例子 這裡說明一點比較常用繼承來實現介面,以為比較簡單化。package test import org.junit.test public class testthread catch interruptedexcepti...
Java多執行緒的初步認識
在談執行緒之前,我們至少應該了解下程序是什麼,簡單來說,程序就是正在執行的應用程式,每乙個正在執行的應用程式就會對應乙個程序。那麼執行緒,就是依賴於程序而存在的,乙個程序可以開啟多個執行緒,由乙個物件所開啟的所有執行緒使用的是同乙份成員屬性。多執行緒的兩種方案 繼承thread類 實現runable...
執行緒核心物件初步認識
執行緒核心物件 執行緒核心物件初步認識 執行緒核心物件就是乙個包含了執行緒狀態資訊的資料結構。每一次對createthread函式的成功呼叫,系統就會在內部為新的執行緒分配乙個核心物件。系統提供的管理執行緒的函式其實就是依靠訪問執行緒核心物件來實現管理的。執行緒核心物件的基本成員 3.1.1核心物件...