僅作爲Java多線程的複習梳理筆記,如果有錯誤希望大家批評指出
1.使用Java多線程
- 繼承
Thread
類:
public class MyThread extends Thread{
@Override
public void run() {
// 重寫run()方法,這個方法就是線程進入running狀態後要運行的方法
super.run();
System.out.println(Thread.currentThread().getName());
}
public static void main(String[] args) {
// 因爲是繼承自Thread類,所以可以直接創建線程對象
Thread t1 = new MyThread();
Thread t2 = new MyThread();
// 調用start()方法以後,該線程會進入ready狀態
// 操作系統會進行調度,根據調度算法線程可能會進入running狀態
// 只有線程真正進入running狀態以後,CPU纔會執行該線程的代碼
t1.start();
t2.start();
}
}
打印輸出結果:
Thread-1
Thread-0
直接繼承自Thread
類是實現Java多線程最直接的一種方式,因爲是繼承自Thread
類,所以可以直接創建線程對象,線程運行時執行的代碼或者方法需要放在重寫父類的run()
方法裏。
- 實現
Runnable
接口
如果噹噹前類已近有一個父類,這時候就不能再繼承Thread
類,所以可以實現Runnable
接口來使用多線程。
public class MyThread implements Runnable{
@Override
public void run() {
// 實現Runnale類一定要重寫run()方法
// 因爲接口的方法是抽象方法,所以必須得實現
System.out.println(Thread.currentThread().getName());
}
public static void main(String[] args) {
// 創建線程傳入Runnale接口的實例
// 因爲我們實現了Runnale接口,所以MyThread類的實例就是它的實例
// 後面的參數是此線程的線程名
Thread t1 = new Thread(new MyThread(),"線程1");
Thread t2 = new Thread(new MyThread(),"線程2");
t1.start();
t2.start();
}
}
打印結果:
線程1
線程2
2.常用方法
public static void main(String[] args) {
System.out.println(Thread.currentThread());
System.out.println(Thread.currentThread().getPriority());
System.out.println(Thread.currentThread().getName());
System.out.println(Thread.currentThread().getId());
System.out.println(Thread.currentThread().isAlive());
}
輸出:
Thread[main,5,main]
5
main
1
true
Thread.currentThread()
:獲取當前正在運行的線程的指針Thread.getPriority()
:獲取該線程的優先級Thread.getName())
:獲取線程的名字Thread.getId()
:獲取該線程在JVM中的IDThread.isAlive()
:獲取該線程的存活狀態,只要是調用了start()方法以後,無論是該線程處在ready狀態還是running狀態,該線程都是存活狀態。
3.線程休眠
public class MyThread implements Runnable{
@Override
public void run() {
// 分別打印:線程名,休眠開始前系統時間,休眠結束後系統時間
System.out.println(Thread.currentThread().getName());
System.out.println(System.currentTimeMillis());
try {
// 調用Thread.sleep(millis),使當前線程休眠1000毫秒
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(System.currentTimeMillis());
}
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(new MyThread(),"線程1");
Thread t2 = new Thread(new MyThread(),"線程2");
t1.start();
// 調用join()方法以後,其他線程會等待該線程死亡以後再繼續運行
// 其他線程包括主線程,都會處於等待狀態(原理是使用了同步鎖)
t1.join();
t2.start();
}
}
打印結果:
線程1
1523976884092
1523976885092
線程2
1523976885093
1523976886094
可以看到調用Thread.sleep()
方法以後,當前線程就進入一種休眠狀態,也就是說這個線程會什麼也不做的讀過這段時間,要注意的是,該線程並不會釋放同步鎖。
4.優先級
在操作系統中,線程可以劃分優先級,優先級越高的線程的到的CPU資源越多,設置線程優先級有助於操作系統決定下一次選擇哪一個線程來優先執行(但是操作系統調度線程和優先級具有隨機性)
public class MyThread implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(new MyThread(),"線程1");
Thread t2 = new Thread(new MyThread(),"線程2");
// 優先級劃分等級從1-10
// 不在這個範圍之內會拋出異常
t1.setPriority(1);
t2.setPriority(10);
t1.start();
t2.start();
}
}
打印結果:
線程2
線程1
當然也有可能打印結果:
線程1
線程2
因爲:
- 線程優先級和代碼執行順序無關,但往往優先級高的線程完成同樣的任務,結束時間要高於優先級低的線程(因爲CPU資源分配更多)
- 優先級不代表優先執行該線程,而只是操作系統會盡量給予更多地CPU運算能力。
5.總結
- Java線程的本質:在JDK1.2以前,Java曾經使用自己的
Green Thread
實現了用戶級別的線程(ULP),但是由於用戶級別的線程存在種種問題(比如線程阻塞時和進程就會出現不一致問題),JDK1.2以後,JVM選擇了交給操作系統進行線程管理(通過系統調用),也就是操作系統中常說的輕量級進程(LWP)。對於Windows系統,明確的劃分了進程和線程兩種數據結構,進行了較好的多線程實現,對於Linux系統,依舊是使用了進程的方式實現了線程。 - Java線程模型和操作系統線程的關係:參考我的另一篇文章–Java線程和操作系統線程的關係