從線程狀態 的圖中可以發現,在Java實現多線程的程序中,雖然Thread類實現了Runnable接口,但是操作線程的主要方法並不在Runnable接口中,而是在Thread類中。
Thread類中主要方法
方法名稱 | 類型 | 概述 |
---|---|---|
public Thread(Runnable target) | 構造 | 接收Runnable接口子類對象,實例化Thread對象 |
public Thread(Runnable target,String name) | 構造 | 接收Runnable接口子類對象,實例化Thread對象,並設置線程名稱 |
public void run() | 普通 | 執行線程 |
。。。。 | 。。 | 。。。。 |
public final void setDemo(boolean on) | 普通 | 將一個線程設置成後臺運行 |
下面介紹幾種常用的線程操作方法。
- 取得和設置線程的名稱
在Thread類中可以通過getName()方法取得線程的名稱,還可以通過setName()方法設置線程的名稱。
線程的名稱一般在啓動線程前就設置,但是也可以爲在運行的線程設置名稱。允許兩個線程擁有相同的名稱,但應該儘量避免這種情況的發生。
如果沒有設置線程的名稱,系統會爲其自動分配名稱。
【取得和設置線程的名稱】
class MyThread implements Runnable{
public void run(){
for(int i=0;i<3;i++){
System.out.println(Thread.currentThread().getName()+
"運行,i="+i);//取得線程的名稱
}
}
};
public class ThreadNameDemo{
public static void main(String args[]){
MyThread my=new MyThread();//定義Runnable子類對象
new Thread(my).start();//系統自動設置線程的名稱
new Thread(my,"線程-A").start();//手動設置線程的名稱
new Thread(my,"線程-B").start();
new Thread(my).start();
}
}
運行結果:
線程-A運行,i=0
Thread-1運行,i=0
線程-B運行,i=0
線程-B運行,i=1
線程-B運行,i=2
Thread-0運行,i=0
Thread-1運行,i=1
線程-A運行,i=1
Thread-1運行,i=2
Thread-0運行,i=1
Thread-0運行,i=2
線程-A運行,i=2
從程序的運行結果中可以發現,沒有設置線程名稱的線程對象也有了名字而且都是有規律的,分別是Thread-1、Thread-0,從之前講解的static關鍵字可以知道,在Thread類中避讓存在一個static類型的屬性,用於爲線程的命名。
瞭解了以上代碼後,下面觀察以下的代碼
【觀察代碼的輸出】
class MyThread implements Runnable
{
public void run(){
for (int i=0;i<3 ;i++ )
{
//取得當前線程的名字
System.out.println(Thread.currentThread().getName()+"運行, i="+i);
}
}
}
public class CurrentThreadDemo
{
public static void main(String args[])
{
MyThread my=new MyThread();//定義Runnable子類對象
new Thread(my,"線程").start();//啓動線程
my.run();//直接使用run方法
}
}
運行結果:
main運行, i=0
線程運行, i=0
main運行, i=1
main運行, i=2
線程運行, i=1
線程運行, i=2
在以上程序中,主方法直接通過Runnable接口的子類對象調用其中的run()方法,另外一個是通過線程對象調用start()方法啓動的,從結果中可以發現,主方法實際上也是一個線程。
另外要提醒的是,在java中所有的現車都是同時啓動的,哪個線程先搶到了CPU的資源,哪個線程就先運行。
說明:Java程序中每次裕興程序至少啓動兩個線程。 從之前的學習中可以知道,每當使用Java命令執行一個類時,實際上都會啓動一個JVM,每個JVM實際上就是在操作系統中啓動了一個進程,,Java本身具有垃圾回收機制。所以在Java運行時至少會啓動兩個線程,一個main線程,另一個就是垃圾收集線程。
2. 判斷線程是否啓動
通過前面的講解可知,通過Thread類中的start()方法通知CPU這個線程已經準備好啓動了,然後等待CUP資源,運行此線程,在Java中可以使用isAlive()方法來測試是否已經啓動而且任然在運行。
【判斷線程是否啓動】
class MyThread implements Runnable{
public void run(){//覆寫run()方法
for(int i=0;i<3;i++){
System.out.println(Thread.currentThread().getName()+
"運行,i="+i);//取得線程的名稱
}
}
};
public class ThreadAliveDemo
{
public static void main(String args[])
{
MyThread my = new MyThread();//實例化Runnable子類對象
Thread t=new Thread(my,"線程");//實例化Thread對象
System.out.println("線程開始執行之前--》"+t.isAlive());//判斷線程是否啓動
t.start();//啓動線程
System.out.println("線程開始執行之後——》"+t.isAlive());//判斷線程是否啓動
for (int i=0;i<3 ;i++ )//循環輸出三次
{
System.out.println("main 運行--》"+i);
}
System.out.println("代碼執行之後--》"+t.isAlive());//後面的輸出結果不確定
}
}
運行結果:
線程開始執行之前--》false
線程開始執行之後——》true
main 運行--》0
main 運行--》1
main 運行--》2
代碼執行之後--》true
線程運行,i=0
線程運行,i=1
線程運行,i=2
以上的代碼運行結果是不確定的,有可能到最後線程已經不存活了,但也有可能繼續存活,這要看哪個線程先運行。因爲線程操作的不確定性,所以當主線程結束時,那麼其他線程不會受到影響,並不會隨着主線程的結束而結束。
3. 線程的強制運行
在線程操作中,可以使用join()方法讓一個線程強制運行,線程強制運行期間,其他線程無法運行,必須等待此線程完成之後才能繼續執行。
【線程的強制運行】
class MyThread implements Runnable
{
public void run(){
for (int i=0;i<20 ;i++ )
{
System.out.println(Thread.currentThread().getName()+"運行--》"+i);
}
}
};
public class ThreadJoinDemo
{
public static void main(String args[])
{
MyThread my=new MyThread();
Thread t=new Thread(my,"線程");
t.start();
for (int j=0;j<10 ;j++ )
{
if (j>5)
{
try
{
t.join();//強制t進行強制進行
}
catch (Exception e)
{
}
}
System.out.println("Main 線程運行-->"+j);
}
}
}
運行結果:
Main 線程運行-->0
線程運行--》0
Main 線程運行-->1
Main 線程運行-->2
Main 線程運行-->3
線程運行--》1
Main 線程運行-->4
線程運行--》2
Main 線程運行-->5
線程運行--》3
線程運行--》4
線程運行--》5
線程運行--》6
線程運行--》7
線程運行--》8
線程運行--》9
線程運行--》10
線程運行--》11
線程運行--》12
線程運行--》13
線程運行--》14
線程運行--》15
線程運行--》16
線程運行--》17
線程運行--》18
線程運行--》19
Main 線程運行-->6
Main 線程運行-->7
Main 線程運行-->8
Main 線程運行-->9
從上面的結果可以看出,主線程必須等待這個強制運行的線程完成之後纔會繼續執行。
4. 線程的休眠
在程序中允許一個線程進行暫時休眠,直接調用Thread.sleep()方法即可實現休眠。
【線程的休眠】
class MyThread implements Runnable
{
public void run(){
for (int i=0;i<5 ;i++ )
{
try
{
Thread.sleep(500);//線程休眠
}
catch (Exception e)
{
}
System.out.println(Thread.currentThread().getName()+"運行,i="+i);
}
}
};
public class ThreadSleepDemo
{
public static void main(String args[])
{
MyThread my=new MyThread();//實例化對象
new Thread(my,"線程").start();//啓動線程
}
}
運行結果:
線程運行,i=0
線程運行,i=1
線程運行,i=2
線程運行,i=3
線程運行,i=4
以上程序在執行時,每次輸出都會間隔500ms,達到延遲操作的效果。
5. 中斷線程
當一個線程運行時,另一個線程可以通過interrupt()方法即可實現休眠。
【線程的中斷】
class MyThread implements Runnable
{
public void run(){
System.out.println("1、進入run方法 ");
try
{
Thread.sleep(10000);//休眠10s
System.out.println("2、已經完成休眠");
}
catch (Exception e)
{
System.out.println("3、休眠被終止了");
return;//讓程序返回被調用處
}
}
}
public class ThreadInterruptDemo
{
public static void main(String args[])
{
MyThread my=new MyThread();//實例化Runnable接口對象
Thread t=new Thread(my,"線程");//實例化線程對象
t.start();
try
{
Thread.sleep(2000);//停止2S後再中斷
}
catch (Exception e)
{
}
t.interrupt();//中斷線程
}
}
運行結果:
1、進入run方法
3、休眠被終止了
從以上程序運行的結果可以看出,一個線程啓動之後進入了休眠狀態,原本是休眠10s後繼續運行,但是主方法在線程啓動的2s後就將其中斷了,休眠一旦中斷,就執行catch中的代碼,並利用裏面的return語句返回程序的調用處。
6. 後臺線程
在Java程序中,只要前臺有一個線程在運行,則整個Java進程就不會消失,所以此時可以設置一個後臺線程,這樣Java進程結束了,此後臺線程依然會繼續執行。使用setDaemon()方法即可。
【後臺線程的設置】
class MyThread implements Runnable
{
public void run(){
while (true)//無限循環
{
System.out.println(Thread.currentThread().getName()+"在運行。");
}
}
}
public class ThreadDaemonDemo
{
public static void main(String args[])
{
MyThread my=new MyThread();
Thread t=new Thread(my,"線程");
t.setDaemon(true);//設置爲後臺線程
t.start();
}
}
在線程MyThread類中,儘管run()方法中是死循環的方式,但是程序依然可以執行完,因爲方法在中死循環的線程操作已經設置爲了後臺運行了。
7. 線程的優先級
在Java的線程操作中,所有的線程在運行前都會保持在就緒狀態,那麼此時,哪個線程的優先級高,哪個線程就可能會先被執行。
線程的優先級:
優先級越高,越有可能先執行。
在Java的線程中使用setPriority()方法可以設置一個線程的優先級,在Java的線程中一共有3中優先級:
定義 | 描述 | 表示的常量 |
---|---|---|
public static final MIN_PRIORITY | 最低優先級 | 1 |
public static final NORM_PRIORITY | 中等優先級,線程的默認優先級 | 5 |
public static final MAX_PRIORITY | 最高優先級 | 10 |
不同優先級的線程執行結果。
【測試線程優先級】
class MyThread implements Runnable
{
public void run(){
for (int i=0;i<5 ;i++ )
{
try
{
Thread.sleep(500);
}
catch (Exception e)
{
}
System.out.println(Thread.currentThread().getName()+"運行,i="+i);
}
}
};
public class ThreadPriorityDemo
{
public static void main(String[] args)
{
Thread t1=new Thread(new MyThread(),"線程A");
Thread t2=new Thread(new MyThread(),"線程B");
Thread t3=new Thread(new MyThread(),"線程C");
t1.setPriority(Thread.MIN_PRIORITY);//設置優先級爲最低優先級
t2.setPriority(Thread.MAX_PRIORITY);//設置優先級爲最高優先級
t3.setPriority(Thread.NORM_PRIORITY);//設置優先級爲中等優先級
t1.start();
t2.start();
t3.start();
}
}
運行結果:
線程B運行,i=0
線程A運行,i=0
線程C運行,i=0
線程B運行,i=1
線程C運行,i=1
線程A運行,i=1
線程B運行,i=2
線程C運行,i=2
線程A運行,i=2
線程B運行,i=3
線程A運行,i=3
線程C運行,i=3
線程B運行,i=4
線程C運行,i=4
線程A運行,i=4
從上面的運行結果可以觀察到,線程將根據其優先級的大小來決定哪個線程會先運行,但是讀者一定要注意的是,並非線程的優先級越高就一定優先執行,哪個線程先執行將由CPU決定。
主線程的優先級是NORM_PRIORITY
8. 線程的禮讓
在線程操作中,也可以使用yield()方法將一個線程的操作暫時讓給其他線程執行。
【線程的禮讓】
class MyThread implements Runnable
{
public void run(){
for (int i=0;i<5 ;i++ )
{
System.out.println(Thread.currentThread().getName()+"運行-->"+i);
if (i==2)
{
System.out.print("線程禮讓:");
Thread.currentThread().yield();//線程禮讓
}
}
}
};
public class ThreadYieldDemo
{
public static void main(String args[])
{
MyThread my=new MyThread();
Thread t1=new Thread(my,"線程A");
Thread t2=new Thread(my,"線程B");
t1.start();
t2.start();
}
}
運行結果:
線程A運行-->0
線程B運行-->0
線程B運行-->1
線程B運行-->2
線程禮讓:線程A運行-->1
線程A運行-->2
線程禮讓:線程B運行-->3
線程B運行-->4
線程A運行-->3
線程A運行-->4
從結果就可以發現,每當線程滿足條件時(i==2),就會將本線程暫停,而讓其他線程先執行。
好了,以上就是線程常用的幾種操作了。