在多線程中所有的操作方法都是從Thread類開始的,所有的操作基本上都在Thread類中。
1,線程名稱
1,在Thread類中可以通過getName()方法取得線程名稱,通過setName()設置線程名稱。
2,線程的名稱一般在啟動線程前設置,但也允許為運行的線程設置名稱,允許兩個Thread對象有相同名稱,但是應該避免。
3,如果程序沒有為線程指定名稱,系統會自動為線程設置名稱。
class MyThread implements Runnable{ // 實現Runnable接口 public void run(){ // 覆寫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 mt = new MyThread() ; // 實例化Runnable子類對象 new Thread(mt).start() ; // 系統自動設置線程名稱 new Thread(mt,"線程-A").start() ; // 手工設置線程名稱 new Thread(mt,"線程-B").start() ; // 手工設置線程名稱 new Thread(mt).start() ; // 系統自動設置線程名稱 new Thread(mt).start() ; // 系統自動設置線程名稱 } };
currentThread(),獲取當前線程。
運行結果:
線程-A運行,i = 0 線程-B運行,i = 0 Thread-1運行,i = 0 Thread-0運行,i = 0 Thread-0運行,i = 1 Thread-0運行,i = 2 Thread-1運行,i = 1 線程-B運行,i = 1 Thread-2運行,i = 0 線程-A運行,i = 1 Thread-2運行,i = 1 線程-B運行,i = 2 Thread-1運行,i = 2 Thread-2運行,i = 2 線程-A運行,i = 2
從效果看,指定的名稱會自動出現,如果沒有指定會發現線程使用自動編號完成,按照Thread-0,Thread-1.依次編號,實際上,肯定在類中存在static屬性,用於記錄編號。
2,當前線程:CurrentThread()
程序可以通過currentThread()方法取得當前正在運行的線程對象,
class MyThread implements Runnable{ // 實現Runnable接口 public void run(){ // 覆寫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 mt = new MyThread() ; // 實例化Runnable子類對象 new Thread(mt,"線程").start() ; // 啟動線程 mt.run() ; // 直接調用run()方法 } };
運行結果:
main運行,i = 0 線程運行,i = 0 main運行,i = 1 線程運行,i = 1 main運行,i = 2 線程運行,i = 2
此時發現,程序中由主方法直接通過線程對象調用里面的run()方法,所有此時的結果包含一個"main",此線程就是由“mt.run()”產生的,因為調用此語句是由主方法完成的。
也就是說,主方法本身也是一個線程---主線程。
問題:既然主方法都是以線程的形式出現,那么JAVA啟動時候運行了多少線程?
回答:至少啟動了兩個。
從之前學習的情況來看,每當JAVA執行,都會啟動一個JVM,每一個JVM都是在操作系統中啟動一個線程。
JAVA本身有垃圾回收機制,所以至少啟動了兩個線程:主線程,GC。
3,判斷線程是否在執行:isAlive
class MyThread implements Runnable{ // 實現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 mt = new MyThread() ; // 實例化Runnable子類對象 Thread t = new Thread(mt,"線程"); // 實例化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 線程運行,i = 0 代碼執行之后 --> true 線程運行,i = 1 線程運行,i = 2
4,線程強制運行:join()
可以通過join()方法使得一個線程強制運行,線程強制運行期間,其他線程無法運行,必須等待此線程完成之后,才可以繼續運行。
package Thread1; class MyThread implements Runnable{ // 實現Runnable接口 public void run(){ // 覆寫run()方法 for(int i=0;i<50;i++){ System.out.println(Thread.currentThread().getName() + "運行,i = " + i) ; // 取得當前線程的名字 } } }; public class demo1{ public static void main(String args[]){ MyThread mt = new MyThread() ; // 實例化Runnable子類對象 Thread t = new Thread(mt,"線程"); // 實例化Thread對象 t.start() ; // 啟動線程 for(int i=0;i<50;i++){ if(i>10){ try{ t.join() ; // 線程強制運行 }catch(InterruptedException e){} } System.out.println("Main線程運行 --> " + i) ; } } };
運行結果:
線程運行,i = 0 Main線程運行 --> 0 線程運行,i = 1 Main線程運行 --> 1 線程運行,i = 2 Main線程運行 --> 2 線程運行,i = 3 線程運行,i = 4 線程運行,i = 5 線程運行,i = 6 線程運行,i = 7 線程運行,i = 8 線程運行,i = 9 Main線程運行 --> 3 線程運行,i = 10 Main線程運行 --> 4 線程運行,i = 11 線程運行,i = 12 線程運行,i = 13 Main線程運行 --> 5 線程運行,i = 14 Main線程運行 --> 6 線程運行,i = 15 線程運行,i = 16 線程運行,i = 17 線程運行,i = 18 線程運行,i = 19 Main線程運行 --> 7 線程運行,i = 20 Main線程運行 --> 8 線程運行,i = 21 Main線程運行 --> 9 線程運行,i = 22 Main線程運行 --> 10 線程運行,i = 23 線程運行,i = 24 線程運行,i = 25 線程運行,i = 26 線程運行,i = 27 線程運行,i = 28 線程運行,i = 29 線程運行,i = 30 線程運行,i = 31 線程運行,i = 32 線程運行,i = 33 線程運行,i = 34 線程運行,i = 35 線程運行,i = 36 線程運行,i = 37 線程運行,i = 38 線程運行,i = 39 線程運行,i = 40 線程運行,i = 41 線程運行,i = 42 線程運行,i = 43 線程運行,i = 44 線程運行,i = 45 線程運行,i = 46 線程運行,i = 47 線程運行,i = 48 線程運行,i = 49 Main線程運行 --> 11 Main線程運行 --> 12 Main線程運行 --> 13 Main線程運行 --> 14 Main線程運行 --> 15 Main線程運行 --> 16 Main線程運行 --> 17 Main線程運行 --> 18 Main線程運行 --> 19 Main線程運行 --> 20 Main線程運行 --> 21 Main線程運行 --> 22 Main線程運行 --> 23 Main線程運行 --> 24 Main線程運行 --> 25 Main線程運行 --> 26 Main線程運行 --> 27 Main線程運行 --> 28 Main線程運行 --> 29 Main線程運行 --> 30 Main線程運行 --> 31 Main線程運行 --> 32 Main線程運行 --> 33 Main線程運行 --> 34 Main線程運行 --> 35 Main線程運行 --> 36 Main線程運行 --> 37 Main線程運行 --> 38 Main線程運行 --> 39 Main線程運行 --> 40 Main線程運行 --> 41 Main線程運行 --> 42 Main線程運行 --> 43 Main線程運行 --> 44 Main線程運行 --> 45 Main線程運行 --> 46 Main線程運行 --> 47 Main線程運行 --> 48 Main線程運行 --> 49
3.5 線程的休眠
在線程中允許一個線程進行暫時的休眠,直接使用Thread.sleep()方法即可。
sleep定義格式:
public static void sleep(long milis,int nanos) throws InterruptedException
首先,static,說明可以由Thread類名稱調用,其次throws表示如果有異常要在調用此方法處處理異常。
所以sleep()方法要有InterruptedException 異常處理,而且sleep()調用方法通常為Thread.sleep(500) ;形式。
例子:
package Thread1; class MyThread implements Runnable{ // 實現Runnable接口 public void run(){ // 覆寫run()方法 for(int i=0;i<50;i++){ try{ Thread.sleep(500) ; // 線程休眠 }catch(InterruptedException e){} System.out.println(Thread.currentThread().getName() + "運行,i = " + i) ; // 取得當前線程的名字 } } }; public class demo1{ public static void main(String args[]){ MyThread mt = new MyThread() ; // 實例化Runnable子類對象 Thread t = new Thread(mt,"線程"); // 實例化Thread對象 t.start() ; // 啟動線程 } };
會發現運行過程中,線程名是一個個間隔一定時間出來的,這里達到了休眠效果。
線程運行,i = 0 線程運行,i = 1 線程運行,i = 2 線程運行,i = 3 線程運行,i = 4 線程運行,i = 5 線程運行,i = 6 線程運行,i = 7 線程運行,i = 8 線程運行,i = 9 線程運行,i = 10 線程運行,i = 11 線程運行,i = 12 線程運行,i = 13 線程運行,i = 14 線程運行,i = 15 線程運行,i = 16 線程運行,i = 17 線程運行,i = 18 線程運行,i = 19 線程運行,i = 20 線程運行,i = 21 線程運行,i = 22 線程運行,i = 23 線程運行,i = 24 線程運行,i = 25 線程運行,i = 26 線程運行,i = 27 線程運行,i = 28 線程運行,i = 29 線程運行,i = 30 線程運行,i = 31 線程運行,i = 32 線程運行,i = 33 線程運行,i = 34 線程運行,i = 35 線程運行,i = 36 線程運行,i = 37 線程運行,i = 38 線程運行,i = 39 線程運行,i = 40 線程運行,i = 41 線程運行,i = 42 線程運行,i = 43 線程運行,i = 44 線程運行,i = 45 線程運行,i = 46 線程運行,i = 47 線程運行,i = 48 線程運行,i = 49
3.6 線程的中斷
一個線程可以被另一個線程中斷其操作的狀態,使用 interrupt()方法完成。
package Thread1; class MyThread implements Runnable{ // 實現Runnable接口 public void run(){ // 覆寫run()方法 System.out.println("1、進入run()方法") ; try{ Thread.sleep(10000) ; // 線程休眠10秒 System.out.println("2、已經完成了休眠") ; }catch(InterruptedException e){ System.out.println("3、休眠被終止") ; } System.out.println("4、run()方法正常結束") ; } }; public class demo1{ public static void main(String args[]){ MyThread mt = new MyThread() ; // 實例化Runnable子類對象 Thread t = new Thread(mt,"線程"); // 實例化Thread對象 t.start() ; // 啟動線程 try{ Thread.sleep(2000) ; // 線程休眠2秒 }catch(InterruptedException e){ System.out.println("3、休眠被終止") ; } t.interrupt() ; // 中斷線程執行 } };
運行結果:
1、進入run()方法 3、休眠被終止 4、run()方法正常結束
會看到,在1到3的時候會因為線程休眠2秒而卡頓了一下。
但是,既然線程中斷了,那么4,這句話不應該打出來的,因此要在3,線程被終止處添加一句話rutrun,表示返回調用處。
package Thread1; class MyThread implements Runnable{ // 實現Runnable接口 public void run(){ // 覆寫run()方法 System.out.println("1、進入run()方法") ; try{ Thread.sleep(10000) ; // 線程休眠10秒 System.out.println("2、已經完成了休眠") ; }catch(InterruptedException e){ System.out.println("3、休眠被終止") ; return ; // 返回調用處 } System.out.println("4、run()方法正常結束") ; } }; public class demo1{ public static void main(String args[]){ MyThread mt = new MyThread() ; // 實例化Runnable子類對象 Thread t = new Thread(mt,"線程"); // 實例化Thread對象 t.start() ; // 啟動線程 try{ Thread.sleep(2000) ; // 線程休眠2秒 }catch(InterruptedException e){ System.out.println("3、休眠被終止") ; } t.interrupt() ; // 中斷線程執行 } };
運行結果:
1、進入run()方法
3、休眠被終止
3.7 后台線程
在Java中,只要一個線程沒有執行完(一個線程在運行),則整個Java的進程不會消失,所以此時可以設置一個后台線程,這樣即使java線程結束了,則后台線程
依舊會繼續執行。要想實現這個操作,要使用setDaemon()方法完成。
t.setDaemon(true) ;
class MyThread implements Runnable{ // 實現Runnable接口 public void run(){ // 覆寫run()方法
int i=0; while(true){ //設置死循環,這樣來實現線程不斷運行,設置后台運行。 System.out.println(Thread.currentThread().getName() + "在運行。"+i) ; } } }; public class ThreadDaemonDemo{ public static void main(String args[]){ MyThread mt = new MyThread() ; // 實例化Runnable子類對象 Thread t = new Thread(mt,"線程"); // 實例化Thread對象 t.setDaemon(true) ; // 此線程在后台運行 t.start() ; // 啟動線程 } };
3.8線程的優先級
獲取優先級的方法:getPriority();
優先級分為最低,最高,普通三個(Thread.MIN_PRIORITY,Thread.MAX_PRIORITY,Thread.NORM_PRIORITY),
設置優先級:
MyThread t1=new MyThread(); Thread t3 = new Thread(t1,"線程C") ;//實例化線程對象 t3.setPriority(Thread.MIN_PRIORITY) ;//設置優先級為最低
例子:
package Thread1; class MyThread implements Runnable{ // 實現Runnable接口 public void run(){ // 覆寫run()方法 for(int i=0;i<5;i++){ try{ Thread.sleep(500) ; // 線程休眠 }catch(InterruptedException e){} System.out.println(Thread.currentThread().getName() + "運行,i = " + i) ; // 取得當前線程的名字 } } }; public class demo1{ 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 線程C運行,i = 0 線程A運行,i = 0 線程B運行,i = 1 線程C運行,i = 1 線程A運行,i = 1 線程B運行,i = 2 線程A運行,i = 2 線程C運行,i = 2 線程B運行,i = 3 線程C運行,i = 3 線程A運行,i = 3 線程B運行,i = 4 線程C運行,i = 4 線程A運行,i = 4
主方法的優先級
主方法的優先級是NORM_PRIORITY.
package Thread1; public class demo1{ public static void main(String args[]){ System.out.println("主方法的優先級:" + Thread.currentThread().getPriority()) ; // 取得主方法的優先級 System.out.println("MAX_PRIORITY = " + Thread.MAX_PRIORITY) ; System.out.println("NORM_PRIORITY = " + Thread.NORM_PRIORITY) ; System.out.println("MIN_PRIORITY = " + Thread.MIN_PRIORITY) ; } };
運行結果:
主方法的優先級:5 MAX_PRIORITY = 10 NORM_PRIORITY = 5 MIN_PRIORITY = 1
由此可知,主方法優先級是5,也就是普通優先級,而且主方法是一個線程對象。
3.9 線程的禮讓
yield()方法實現線程的禮讓。
package Thread1; class MyThread implements Runnable{ // 實現Runnable接口 public void run(){ // 覆寫run()方法 for(int i=0;i<5;i++){ try{ Thread.sleep(500) ; //休眠一下 }catch(Exception e){} System.out.println(Thread.currentThread().getName() + "運行,i = " + i) ; // 取得當前線程的名字 if(i==2){ System.out.print("線程禮讓:") ; Thread.currentThread().yield() ; // 首先獲取當前線程,然后線程禮讓 } } } }; public class demo1{ public static void main(String args[]){ MyThread my = new MyThread() ; // 實例化MyThread對象 Thread t1 = new Thread(my,"線程A") ; Thread t2 = new Thread(my,"線程B") ; t1.start() ; t2.start() ; } };
運行結果:
線程A運行,i = 0 線程B運行,i = 0 線程B運行,i = 1 線程A運行,i = 1 線程A運行,i = 2 線程禮讓:線程B運行,i = 2 線程禮讓:線程A運行,i = 3 線程B運行,i = 3 線程A運行,i = 4 線程B運行,i = 4