一、多線程
1.並發與並行
-
-
並行:指兩個或多個事件在同一時刻發生(同時發生)。
2.線程和進程
-
-
線程:線程是進程中的一個執行單元,負責當前進程中程序的執行,一個進程中至少有一個線程。一個進程中是可以有多個線程的,這個應用程序也可以稱之為多線程程序。
3.1.創建線程一
2)創建Thread子類的實例,即創建了線程對象
3)調用線程對象的start()方法來啟動該線程
例:
public class MyThread extends Thread { //定義指定線程名稱的構造方法 public MyThread(String name) { //調用父類的String參數的構造方法,指定線程的名稱 super(name); } /** * 重寫run方法,完成該線程執行的邏輯 */ @Override public void run() { for (int i = 0; i < 10; i++) { System.out.println(getName()+":正在執行!"+i); } } public static void main(String[] args) { //創建自定義線程對象 MyThread mt = new MyThread("新的線程!"); //開啟新線程 mt.start(); //在主方法中執行for循環 for (int i = 0; i < 10; i++) { System.out.println("main線程!"+i); } } }
3.1.1.Thread類的構造方法
public Thread() :分配一個新的線程對象。
public Thread(String name) :分配一個指定名字的新的線程對象。
public Thread(Runnable target) :分配一個帶有指定目標新的線程對象。
public Thread(Runnable target,String name) :分配一個帶有指定目標新的線程對象並指定名字
3.1.2.常用方法
public String getName() :獲取當前線程名稱。
public void start() :導致此線程開始執行; Java虛擬機調用此線程的run方法。
public void run() :此線程要執行的任務在此處定義代碼。
public static void sleep(long millis) :使當前正在執行的線程以指定的毫秒數暫停(暫時停止執行)。
public static Thread currentThread() :返回對當前正在執行的線程對象的引用。
3.2.創建線程二
1. 定義Runnable接口的實現類,並重寫該接口的run()方法,該run()方法的方法體同樣是該線程的線程執行體。
2. 創建Runnable實現類的實例,並以此實例作為Thread的target來創建Thread對象,該Thread對象才是真正 的線程對象。
3. 調用線程對象的start()方法來啟動線程
例:
3.3.Thread和Runnable的區別
如果一個類繼承Thread,則不適合資源共享。但是如果實現了Runable接口的話,則很容易的實現資源共享;
實現Runnable接口比繼承Thread類所具有的優勢:
1. 適合多個相同的程序代碼的線程去共享同一個資源。
2. 可以避免java中的單繼承的局限性。
3. 增加程序的健壯性,實現解耦操作,代碼可以被多個線程共享,代碼和線程獨立。
4. 線程池只能放入實現Runable或Callable類線程,不能直接放入繼承Thread的類。
4.線程的同步
4.1.同步代碼塊: synchronized 關鍵字可以用於方法中的某個區塊中,表示只對這個區塊的資源實行互斥訪問。
例:
同步鎖:
1. 鎖對象 可以是任意類型。
2. 多個線程對象 要使用同一把鎖。
注意:在任何時候,最多允許一個線程擁有同步鎖,誰拿到鎖就進入代碼塊,其他的線程只能在外等着
4.2.同步方法
- 同步方法:使用synchronized修飾的方法,就叫做同步方法,保證A線程執行該方法的時候,其他線程只能在方法外 等着。
格式:
同步鎖:
對於非static方法,同步鎖就是this。
對於static方法,我們使用當前方法所在類的字節碼對象(類名.class)
4.3.Lock鎖
- Lock比synchronized代碼塊和synchronized方法更廣泛的鎖定操作, 同步代碼塊/同步方法具有的功能Lock都有,除此之外更強大,更體現面向對象。
1) public void lock() :加同步鎖。
2) public void unlock() :釋放同步鎖
3)Lock接口的實現類ReentrantLock
例:
5.線程狀態
二、線程池
1.等待喚醒機制
-
wait:線程不再活動,不再參與調度,進入 wait set 中,因此不會浪費 CPU 資源,也不會去競爭鎖了,這時的線程狀態即是 WAITING。它還要等着別的線程執行一個特別的動作,也即是“通知(notify)”在這個對象上等待的線程從wait set 中釋放出來,重新進入到調度隊列(ready queue)中
-
notify:則選取所通知對象的 wait set 中的一個線程釋放;例如,餐館有空位置后,等候就餐最久的顧客最先入座。
-
notifyAll:則釋放所通知對象的 wait set 上的全部線程。
-
wait方法與notify方法必須要由同一個鎖對象調用。因為:對應的鎖對象可以通過notify喚醒使用同一個鎖對象調用的wait方法后的線程。
-
wait方法與notify方法是屬於Object類的方法的。因為:鎖對象可以是任意對象,而任意對象的所屬類都是繼承了Object類的。
-
wait方法與notify方法必須要在同步代碼塊或者是同步函數中使用。因為:必須要通過鎖對象調用這2個方法。
2.線程池
線程池優點:
-
-
提高響應速度。當任務到達時,任務可以不需要的等到線程創建就能立即執行。
-
提高線程的可管理性。可以根據系統的承受能力,調整線程池中工作線線程的數目,防止因為消耗過多的內存,而把服務器累趴下(每個線程需要大約1MB內存,線程開的越多,消耗的內存也就越大,最后死機)。
三、Lambda表達式
public class Demo02LambdaRunnable { public static void main(String[] args) { new Thread(() -> System.out.println("多線程任務執行!")).start(); // 啟動線程 } }