java線程基礎梳理
阿新 • • 發佈:2019-01-24
邏輯 yield 暫時 category new t create 繼承 另一個 demo
java線程
概述
- 進程:運行時概念,運行的應用程序,進程間不能共享內存
- 線程:應用程序內並發執行的代碼段,可以共享堆內存和方法區內存,而棧內存是獨立的。
並發理解:在單核機器上,從微觀角度來看,一段時間內cup只能執行一個任務,但是因為cup在只執行一段代碼段的時候大部分的時間是處於等待程序的,所以可以再開幾條程序,然後通過輪詢機制,讓cpu執行多個進程,從宏觀角度來看就是所謂的並發。如果機器是多核,那麽就是真正的並發。
線程調度模型
- 線程的調度模型分為: 分時調度模型和搶占式調度模型,Java使用搶占式調度模型
- 分時調度模型: 所有線程輪流使用CPU的使用權,平均分配每個線程占用CPU的時間片
- 搶占式調度模型: 優先讓優先級高的線程使用CPU,如果線程的優先級相同,那麽會隨機選擇一個,優先級高的線程獲取的CPU時間片相對多一些.
線 程 優 先 級 主 要 分 三 種 : MAX_PRIORITY( 最 高 級 );MIN_PRIORITY ( 最 低 級 )NORM_PRIORITY(標準)默認
java 程序的運行原理?
- java 命令會啟動 java 虛擬機,啟動 JVM,等於啟動了一個應用程序,表示啟動了一個進程。該進程會自動啟動一個“主線程”,然後主線程去調用某個類的 main 方法。所以 main方法運行在主線程中。在此之前的所有程序都是單線程的。
一個棧就是一個線程,所謂的並發就是多個不同的棧。
線程創建
- 繼承Thread
- 線程編寫要繼承 java.lang.Thread
- 重寫run方法
- 調用的時候調用線程類的start()方法,run方法是讓cpu調用的。所以start()方法調用後run方法不會立刻調用。
- 實現runable接口
class CreateRunnable implements Runnable { @Override publicvoid run() { for (inti = 0; i< 10; i++) { System.out.println("i:" + i); } } } public class ThreadDemo2 { publicstaticvoid main(String[] args) { System.out.println("-----多線程創建開始-----"); // 1.創建一個線程 CreateRunnable createThread = new CreateRunnable(); // 2.開始執行線程 註意 開啟線程不是調用run方法,而是start方法 System.out.println("-----多線程創建啟動-----"); Thread thread = new Thread(createThread); thread.start(); } }
- 使用匿名內部調用
System.out.println("-----多線程創建開始-----");
Thread thread = new Thread(new Runnable() {
public void run() {
for (int i = 0; i< 10; i++) {
System.out.println("i:" + i);
}
}
});
thread.start();
System.out.println("-----多線程創建結束-----");
線程分類
- 主線程、子線程、GC線程
- 一個進程中肯定要有主線程。一般是用main函數來創建
- java主線程結束是不影響子線程的。
- GC線程是守護線程。
- 守護線程隨著主線程的銷毀而銷毀。
- 在一個線程start前用thread.setDaemon(true)可以將用戶線程變成守護線程。
- 守護線程和用戶線程
- 從線程分類上可以分為:用戶線程(以上講的都是用戶線程),另一個是守護線程。
- 其它所有的用戶線程結束,則守護線程退出!因為 daemon守護線程是守護非守護線程的
- setDaemon(true) 使線程變成守護線程
- 守護線程一般都是無限執行的.
- 例如 java 中著名的垃圾回收器GC線程就是一個守護線程。
線程安全和鎖
- 任何對象都可以是鎖,因為鎖的本質是參照物,類似於紅綠燈,上課鈴等等,關鍵是大家要看一個參照物。
- 同步代碼塊(以object為鎖)
synchronized(object){
[並發邏輯]
}
- 加鎖裏的邏輯要盡量少
- 同步方法
public synchronized int getTicket(){
}
- 同步方法(非靜態)是以當前對象作為鎖。
- 如果用非靜態同步方法加鎖,一般獨立出一個對象池,將同步方法放在對象池內,然後多線程對象每次從同一個對象池取資源。
- 同步方法(靜態) 是以類作為鎖。
線程生命周期
- yield();方法可以讓線程方法暫時放棄cpu的搶占,但是一旦放棄後又馬上開始搶,有謙讓的意義
- Thread.sleep(time) 靜態方法 讓當前線程休眠time毫秒,不去搶占cpu
join等到指定的線程執行完後執行
sleep() 與 wait()的比較
- 相同點:wait()的作用是讓當前線程由“運行狀態”進入“等待(阻塞)狀態”的同時,也會釋放同步鎖。而sleep()的作用是也是讓當前線程由“運行狀態”進入到“休眠(阻塞)狀態”
不同點:wait()會釋放對象的同步鎖,而sleep()則不會釋放鎖
join()方法作用
當在主線程當中執行到t1.join()方法時,就認為主線程應該把執行權讓給t1
線程死亡
有兩個原因會導致線程死亡:
- 1) run方法正常退出而自然死亡,
- 2) 一個未捕獲的異常終止了run方法而使線程猝死。
- 為了確定線程在當前是否存活著(就是要麽是可運行的,要麽是被阻塞了),需要使用isAlive方法。如果是可運行或被阻塞,這個方法返回true; 如果線程仍舊是new狀態且不是可運行的, 或者線程死亡了,則返回false.
阻塞狀態
- 線程運行過程中,可能由於各種原因進入阻塞狀態:
- 1>線程通過調用sleep方法進入睡眠狀態;
- 2>線程調用一個在I/O上被阻塞的操作,即該操作在輸入輸出操作完成之前不會返回到它的調用者;
- 3>線程試圖得到一個鎖,而該鎖正被其他線程持有;
4>線程在等待某個觸發條件;
參考
- https://www.cnblogs.com/skywang12345/p/java_threads_category.html
java線程基礎梳理