1.實現多線程
1.1進程
進程:是正在運行的程序。
- 是系統進行資源分配和調用的獨立單位;
- 每一個進程都有它自己的內存空間和系統資源。
1.2線程
線程:是進程中的單個順序控制流,是一條執行路經。 - 單線程:一個進程如果只有一條執行路經,則爲單線程程序;
- 多線程:一個進程如果有多條執行路經,則爲多線程程序。
1.3多線程的實現方式
方式1: - 定義一個類MyThread繼承Thread類;
- 在MyThread類中重寫run()方法;
- 創建MyThread類的對象;
- 啓動線程。
1.4設置和獲取線程名稱
Thread類中設置和獲取線程名稱的方法 - void setName(String name):將此線程的名稱更改爲等於參數name;
- String getName():返回此線程的名稱;
- 通過構造方法也可以設置線程名稱。
如何獲取main()方法所在的線程名稱? - public static Thread currentThread():返回對當前正在執行的線程對象的引用。
1.5 線程調度
線程有兩種調度模型: - 分時調度模型:所有線程輪流使用CPU的使用權,平均分配每個線程佔用CPU的時間片;
- 搶佔調度模型:優先讓優先級高的線程使用CPU,如果線程的優先級相同,那麼會隨機選擇一個,優先級高的線程獲取的CPU時間片相對多一些。
Java使用的是搶佔式調度模型。
假如計算機只有一個CPU,那麼CPU在某一時刻只能執行一條指令,線程只有得到CPU時間片,也就是使用權,纔可以執行指令。所以說多線程程序的執行是有隨機性,因爲誰搶到CPU的使用權是不一定的。
Thread類中設置和獲取線程優先級的方法:
- public final int getPriority():返回此線程的優先級;
- public final void setPriority(int new Priority):更改此線程的優先級。
1.6線程控制
方法名 | 說明 |
---|---|
static void sleep(long millis) | 是當前正在執行的線程停留(暫停執行)指定的毫秒數 |
void join() | 等待這個線程死亡 |
void setDaemon(boolean on) | 將此線程標記爲守護線程,當運行的線程都是守護線程時,Java虛擬機將推出 |
1.7 線程生命週期
1.8 多線程的實現方式
方式2:實現Runnable接口
- 定義一個類MyRunnable實現Runnable接口;
- 在MyRunnable類中重寫run()方法;
- 創建MyRunnable類中的對象;
- 創建Thread類的對象,把MyRunnable對象作爲構造方法的參數;
- 啓動線程。
多線程的實現方案有兩種: - 繼承Thread類;
- 實現Runnable接口;
相比繼承Thread類,實現Runnable接口的好處 - 避免了Java單繼承的侷限性;
- 適合多個相同程序的代碼去處理同一個資源的情況,把線程和程序的代碼、數據有效分離,較好的體現了面向對象的設計思想。
2. 線程同步
2.1 數據安全問題
判斷多線程程序是否會有數據安全問題的標準:
- 是否是多線程環境;
- 是否有共享數據;
- 是否有多條語句操作共享數據;
如何解決多線程安全問題?
-
基本思想:讓程序沒有安全問題的環境;
怎麼實現? -
把多條語句操作共享數據的代碼給鎖起來,讓任意時刻只可能有一個線程執行即可。
2.2 同步代碼塊
鎖多條語句操作共享數據,可以使用同步代碼塊實現。 -
格式:
-
synchronized(任意對象){
-
多條語句操作共享數據的代碼
-
}
-
synchronized(任意對象):就相當於給代碼加鎖了,任意對象就可以看成是一把鎖。
同步的好處和弊端: -
好處:解決了多線程的數據安全問題;
-
壞處:當線程很多時,因爲每個線程都會去判斷同步上的鎖,這是很耗費資源的,無形中會降低程序的運行效率。
2.3 同步方法
同步方法:就是把synchronized關鍵字加到方法上。 -
格式:修飾符synchronized返回值類型方法名(方法參數){ }。
同步方法的鎖對象是什麼呢? -
this
同步靜態方法:就是把synchronzed關鍵字加到靜態方法上 -
格式:修飾符 static synchronzed返回值類型 方法名(方法參數){ }
同步靜態方法的鎖對象是什麼呢? -
類名.class
2.4 線程安全的類
StringBuffer -
線程安全,可變的字符序列
-
從版本JDK5開始,被StringBuilder替代。通常應該使用StringBuilder類,因爲它支持所有相同的操作,但它更快,因爲它不執行同步。
Vector -
從Java2平臺v1.2開始,該類改進了List接口,使其成爲Java Collections Framework的成員。與新的集合實現不同,Vector被同步。如果不需要線程安全的實現,建議使用ArrayList代替Vector.
Hashtable -
該類實現了一個哈希表,它將鍵映射到值。任何非null對象都可以用作鍵或者值;
-
從Java2平臺v1.2開始,該類進行了改進,實現了Map接口,使其成爲Java Collections Framework的成員。與新的集合實現不同,Hashtable被同步,如果不需要線程安全的實現,建議使用HashMap代替Hashtable。
2.5 Lock鎖
雖然我們可以理解同步代碼塊和同步方法的鎖對象問題,但是我們並沒有直接看到在哪裏加上了鎖,爲了更清晰的表達如何加鎖,JDK5以後提供了一個新的鎖對象Lock。
Lock實現提供比較使用synchronized方法和語句可以獲得更廣泛的鎖定操作。
Lock中提供了獲得鎖和釋放鎖的方法。 -
void lock():獲得鎖
-
void unlock():釋放鎖
Lock是接口不能直接實例化,這裏採用它的實現類ReentrantLock來實例化。
ReentrantLock的構造方法 -
ReentrantLock():創建一個ReentrantLock的實例。
3.1生產者消費者模式
爲了體現生產者和消費者過程中的等待和喚醒,Java就提供了幾個方法供我們使用,這幾個方法在Object類中。
Object類中的等待和喚醒方法:
方法名 | 說明 |
---|---|
void wait() | 導致當前線程等待,直到另一個線程調用該對象的notify()方法或notifyAll()方法 |
void notify() | 喚醒正在等待對象監視器的單個線程 |
void notifyAll() | 喚醒正在等待對象監視器的所有線程 |