點擊鏈接返回標題->
Java線程的學習-CSDN博客
目錄
前言
有關線程名字的成員方法:
String getName()
void setName(String name)
Thread(String name)
?獲取線程對象的成員方法:
static Thread currentThread()
讓線程睡眠的成員方法:
static void sleep(long time)?throws InterruptedException
有關線程優先級的成員方法
int getPriority()
void setPriority(int newPriority)
守護線程
void setDaemon(boolean on)
禮讓線程
?static void yield()
插入線程?
void join() throws InterruptedException
前言
在上一篇中學習了多線程的3種實現方式,其實已經不可避免地涉及到了Thread類的部分成員方法,有用setName()方法設置線程名字,用getName()方法獲取當前線程名字,以及一個Thread類的靜態方法currentThread()可以獲取到當前線程的實例化對象。
本篇我們就來系統性地學習、記錄一下Thread類中常用的成員方法。
有關線程名字的成員方法:
String getName()
該方法將以String對象返回當前線程的名字。
特殊的,如果未設置線程名,該方法將返回"Thread-number",其中number按線程的實例化順序從0開始編號自增。
特殊的,main方法執行的進程(即主進程)名字默認為main,下面兩張圖驗證了這個說法——
示例代碼:
void setName(String name)
調用該方法時傳入String對象,將為當前線程設置名字,前文已經多次涉及。
Thread(String name)
該方法是Thread類的有參構造方法,在實例化線程對象時傳入String對象可以直接完成線程名字設置。
需要注意的是!通常我們會通過自定義子類繼承Thread類的方式來實現多線程,但子類不會繼承父類的構造方法!因此這種情況下必須使用super關鍵字去調用父類的構造方法。
示例代碼:
部分運行結果:
測試代碼:
public class Main {public static void main(String[] args) {myThread t1 = new myThread();//實例化對象,線程t1myThread t2 = new myThread("有參構造設置名稱");//實例化對象,線程t2并調用有參構造給線程設置名稱t1.setName("線程1");//設置線程t1的名字t1.start();//啟動線程t1t2.start();//啟動線程t2}
}class myThread extends Thread {//自定義子類myThread繼承Thread類myThread() {}myThread(String name) {super(name);System.out.print("有參構造被調用");}@Overridepublic void run() {//重寫run()方法for (int i = 1; i <= 100; i++) {System.out.println("當前線程名字為:" + getName());}}
}
?獲取線程對象的成員方法:
static Thread currentThread()
這個方法可以獲取當前線程的實例化對象,前面已經多次涉及。
對于主線程main,這里補充了一些細節——
- 當JVM虛擬機啟動之后,會自動啟動多條線程
- 其中一條線程就叫main線程
- 它的作用就是去調用main方法,并執行里面的代碼
- 在以前,我們寫的所以代碼,其實都是運行在main線程中(沒有開多線程)
讓線程睡眠的成員方法:
static void sleep(long time)?throws InterruptedException
這個方法是Thread的靜態方法,它的作用時讓當前線程“睡眠”(即暫停運行)time毫秒
注意time的單位是毫秒->1秒(s)等于1000毫秒(ms)
調用該靜態方法的方法需要聲明拋出InterruptedException異常類或者用try...catch...finally語句處理異常,否則代碼無法運行。
示例代碼:
public class Main {public static void main(String[] args) throws InterruptedException {System.out.println("第一句話打印完后main線程睡眠7秒");Thread.sleep(7000);System.out.println("然后繼續打印第二句話");}
}
上面的示例展示了main進程的睡眠,如果是在新開的自定義進程睡眠的話,有些許不同之處。主要原因在于,在Thread這個父類中沒有聲明拋出InterruptedException異常類,所以自定義的子類也不能聲明拋出異常,解決方法是使用try...catch...finally語句進行異常處理
有關異常類見本篇->Java異常-CSDN博客
示例代碼:
部分運行結果:
public class Main {public static void main(String[] args) throws InterruptedException {myThread t1 = new myThread();myThread t2 = new myThread();t1.start();t2.start();}
}class myThread extends Thread {//自定義子類myThread繼承Thread類@Overridepublic void run() {//重寫run()方法for (int i = 1; i <= 100; i++) {System.out.println("當前線程名字為:" + getName());try {Thread.sleep(2000);} catch (InterruptedException e) {throw new RuntimeException(e);}}}
}
有關線程優先級的成員方法
在計算機當中,線程的調度有兩種方式——
- 搶占式調度:這種方式下,線程完全隨機被調度,(假設共3個線程)1完了可能是3,3完了可能是1,接著可能是2,純靠隨機調度(不同線程擁有不同的優先級,優先級越高的線程,被調度的概率越大)。
- 輪流式調度:這種方式下,線程按順序輪流調度,(假設共3個線程)1完了到2,2完了到3,3完了又回到1。
在Java中,運用的是搶占式調度,線程的優先級共10級,級別越大的線程其優先級越高,搶到cpu執行權的概率越大,被調度的概率越大。
下圖展示了Thread類的源碼,其中有3個成員變量,分別表示最低級別1、默認級別5、最高級別10。
int getPriority()
這個方法用來獲取當前線程的優先級,對于未設置過優先級的線程,優先級默認為5
下圖示例代碼驗證了這個說法——
void setPriority(int newPriority)
這個方法用來設置當前線程的優先級,傳入一個1到10之間整數進行設置。
示例代碼:
public class Main {public static void main(String[] args) throws InterruptedException {Thread t = Thread.currentThread();//獲取當前線程(即主線程)的實例化對象System.out.println("主線程的優先級為:" + t.getPriority());//打印當前線程的優先級myThread myt1 = new myThread();myThread myt2 = new myThread();//自定義兩個線程myt1.setName("線程1");myt2.setName("線程2");//設置兩個線程的名字myt1.start();myt2.start();//啟動兩個線程myt1.setPriority(1);myt1.setPriority(10);//分別設置優先級為1和10,顯然線程2的優先級更大,被調度的概率更高}
}class myThread extends Thread {//自定義子類myThread繼承Thread類@Overridepublic void run() {//重寫run()方法for (int i = 1; i <= 100; i++) {System.out.println(getName() + "打印了" + i);}}
}
守護線程
被設置為守護線程的線程將在其它非守護線程執行完畢后,陸續結束執行(注意此處“陸續”的含義,不是立刻結束)
光看定義確實十分抽象,因此舉了一個實際應用場景的例子:
如下圖是很常見的qq傳輸文件場景,對于這個聊天頁面,可以認為是線程1,對于傳送文件這個過程,可以認為是線程2。
在傳輸過程中,如果你突然關閉了這個聊天窗口(即結束了線程1),這個時候線程2就會跟著一起結束執行,這種關系下線程2就被稱為守護線程。
void setDaemon(boolean on)
這個方法用來設置線程為守護線程,傳入一個布爾類型的值true,表示將當前線程設置為守護線程。
代碼示例——
public class Main {public static void main(String[] args) throws InterruptedException {myThread1 t1 = new myThread1();myThread2 t2 = new myThread2();t1.setName("線程1");t2.setName("線程2");//分別命名t2.setDaemon(true);//將線程2設置為守護線程t1.start();t2.start();}
}class myThread1 extends Thread {//這個線程是非守護線程@Overridepublic void run() {//重寫run()方法,打印10次for (int i = 1; i <= 10; i++) {System.out.println(getName() + "打印了" + i);}}
}class myThread2 extends Thread {//這個線程是守護線程@Overridepublic void run() {//重寫run()方法,打印100次for (int i = 1; i <= 100; i++) {System.out.println(getName() + "打印了" + i);}}
}
禮讓線程
在多線程中常常遇到下圖這種情況,連續好幾次一直被同一個線程搶占到cpu的執行權(雖說默認優先等級都是5,但耐不住有的線程比較“歐”)
禮讓線程的含義就是讓當前線程讓出當前的cpu執行權,注意,讓出執行權之后并不是說執行權就一定給別的線程了,而是讓別的線程有更多機會來跟自己搶奪執行權(
我只是給你機會,又沒說一定給你是吧),所以說讓出執行權后又再次搶到的可能也是存在的!
?static void yield()
該靜態成員方法用來禮讓線程,讓出執行權給其它線程更多的執行機會,在一定程度上使執行權均勻分配。
插入線程?
void join() throws InterruptedException
該方法用于將當前線程插入到另一線程之前,被插入的線程結束前不會執行它后面的線程。
調用該靜態方法的方法需要聲明拋出InterruptedException異常類或者用try...catch...finally語句處理異常,否則代碼無法運行。
需要注意的是,插入操作必須寫在啟動操作之后(即先start后join)!