java的重要功能之一就是內部支持多線程,這一系列文章將詳細剖析java多線程的基礎知識
多線程引入
進程:正在運行的程序,是系統進行資源分配和調用的獨立單位。每一個進程都有它自己的內存空間和系統資源。
線程:是進程中的單個順序控制流,是一條執行路徑。一個進程如果只有一條執行路徑,則稱為單線程程序。
一個進程如果有多條執行路徑,則稱為多線程程序。
Java程序運行原理
java 命令會啟動 java 虛擬機,啟動 JVM,等於啟動了一個應用程序,也就是啟動了一個進程。該進程會自動啟動一個 “主線程” ,然後主線程去調用某個類的 main 方法。所以 main方法運行在主線程中。在此之前的所有程序都是單線程的。
java虛擬機是多線程的,因為除了主線程外,還有垃圾回收線程
方式1:繼承Thread類
步驟
1、自定義類MyThread繼承Thread類。
2、MyThread類裡面重寫run()
3、創建對象
4、啟動線程
下面的代碼:
/* * 該類要重寫run()方法,為什麼呢? * 不是類中的所有代碼都需要被線程執行的。 * 而這個時候,為了區分哪些代碼能夠被線程執行,java提供了Thread類中的run()用來包含那些被線程執行的代碼。 */ public class MyThread extends Thread { @Override public void run() { // 一般來說,被線程執行的代碼肯定是比較耗時的。所以我們用循環改進 for (int x = 0; x < 300; x++) { System.out.println(x); } } } public class MyThreadDemo { public static void main(String[] args) { // 創建兩個線程對象 MyThread my1 = new MyThread(); MyThread my2 = new MyThread(); my1.start(); my2.start(); } }
步驟:
1、自定義類MyRunnable實現Runnable接口
2、重寫run()方法
3、創建MyRunnable類的對象
4、創建Thread類的對象,並把C步驟的對象作為構造參數傳遞
public class MyRunnable implements Runnable { @Override public void run() { for (int x = 0; x < 100; x++) { // 由於實現接口的方式就不能直接使用Thread類的方法了,但是可以間接的使用 System.out.println(Thread.currentThread().getName() + ":" + x); } } } /* * 方式2:實現Runnable接口 * 步驟: * A:自定義類MyRunnable實現Runnable接口 * B:重寫run()方法 * C:創建MyRunnable類的對象 * D:創建Thread類的對象,並把C步驟的對象作為構造參數傳遞 */ public class MyRunnableDemo { public static void main(String[] args) { // 創建MyRunnable類的對象 MyRunnable my = new MyRunnable(); // 創建Thread類的對象,並把C步驟的對象作為構造參數傳遞 // Thread(Runnable target) Thread t1 = new Thread(my); Thread t2 = new Thread(my); t1.setName("zhangsan"); t2.setName("lisi"); // Thread(Runnable target, String name) Thread t1 = new Thread(my, "zhangsan"); Thread t2 = new Thread(my, "lisi"); t1.start(); t2.start(); } }
實現接口方式的好處:
1. 可以避免由於Java單繼承帶來的局限性。
2. 適合多個相同程序的代碼去處理同一個資源的情況,把線程同程序的代碼,數據有效分離,較好的體現了面向對象的設計思想。
獲取和設置線程名稱
Thread類的基本獲取和設置方法:
public final String getName() public final void setName(String name)其實通過構造方法也可以給線程起名字
如何獲取main方法所在的線程名稱呢?
public static Thread currentThread()這樣就可以獲取任意方法所在的線程名稱
示例代碼如下:
public class MyThread extends Thread { public MyThread() { } public MyThread(String name){ super(name); } @Override public void run() { for (int x = 0; x < 100; x++) { System.out.println(getName() + ":" + x); } } } public class MyThreadDemo { public static void main(String[] args) { // 創建線程對象 //無參構造+setXxx() MyThread my1 = new MyThread(); MyThread my2 = new MyThread(); // 調用方法設置名稱 my1.setName("zhangsan"); my2.setName("lisi"); my1.start(); my2.start(); //帶參構造方法給線程起名字 MyThread my1 = new MyThread("zhangsan"); MyThread my2 = new MyThread("lisi"); my1.start(); my2.start(); //我要獲取main方法所在的線程對象的名稱,該怎麼辦呢? //public static Thread currentThread():返回當前正在執行的線程對象 System.out.println(Thread.currentThread().getName()); } }
線程調度
假如我們的計算機只有一個 CPU,那麼 CPU 在某一個時刻只能執行一條指令,線程只有得到 CPU時間片,也就是使用權,才可以執行指令。那麼Java是如何對線程進行調用的呢?
線程有兩種調度模型:
Java使用的是搶占式調度模型。
public final int getPriority() public final void setPriority(int newPriority)示例代碼如下:
public class ThreadPriority extends Thread { @Override public void run() { for (int x = 0; x < 100; x++) { System.out.println(getName() + ":" + x); } } } /* * public final int getPriority():返回線程對象的優先級 * 如何設置線程對象的優先級呢? * public final void setPriority(int newPriority):更改線程的優先級。 * * 注意: * 線程默認優先級是5。 * 線程優先級的范圍是:1-10。 * 線程優先級高僅僅表示線程獲取的 CPU時間片的幾率高,但是要在次數比較多,或者多次運行的時候才能看到比較好的效果。 * * */ public class ThreadPriorityDemo { public static void main(String[] args) { ThreadPriority tp1 = new ThreadPriority(); ThreadPriority tp2 = new ThreadPriority(); ThreadPriority tp3 = new ThreadPriority(); tp1.setName("zhangsan"); tp2.setName("lisi"); tp3.setName("wangwu"); // 獲取默認優先級 System.out.println(tp1.getPriority()); System.out.println(tp2.getPriority()); System.out.println(tp3.getPriority()); // 設置線程優先級 // tp1.setPriority(100000); //設置正確的線程優先級 tp1.setPriority(10); tp2.setPriority(1); tp1.start(); tp2.start(); tp3.start(); } }