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();
}
}