1. 程式人生 > >Java總結篇系列:Java多線程(二)

Java總結篇系列:Java多線程(二)

文章 睡眠 blog setdeamon java多線程 cep public pan level

Java總結篇系列:Java多線程(二)

本文承接上一篇文章《Java總結篇系列:Java多線程(一)》。

四.Java多線程的阻塞狀態與線程控制

上文已經提到Java阻塞的幾種具體類型。下面分別看下引起Java線程阻塞的主要方法。

1.join()

join —— 讓一個線程等待另一個線程完成才繼續執行。如A線程線程執行體中調用B線程的join()方法,則A線程被阻塞,知道B線程執行完為止,A才能得以繼續執行。

技術分享
 1 public class ThreadTest {
 2 
 3     public static void main(String[] args) {
 4 
 5         MyRunnable myRunnable = new MyRunnable();
 6         Thread thread = new Thread(myRunnable);
 7 
 8         for (int i = 0; i < 100; i++) {
 9             System.out.println(Thread.currentThread().getName() + " " + i);
10             if (i == 30) {
11                 thread.start();
12                 try {
13                     thread.join();    // main線程需要等待thread線程執行完後才能繼續執行
14                 } catch (InterruptedException e) {
15                     e.printStackTrace();
16                 }
17             }
18         }
19     }
20 }
21 
22 class MyRunnable implements Runnable {
23 
24     @Override
25     public void run() {
26         for (int i = 0; i < 100; i++) {
27             System.out.println(Thread.currentThread().getName() + " " + i);
28         }
29     }
30 }
技術分享

2.sleep()

sleep —— 讓當前的正在執行的線程暫停指定的時間,並進入阻塞狀態。在其睡眠的時間段內,該線程由於不是處於就緒狀態,因此不會得到執行的機會。即使此時系統中沒有任何其他可執行的線程,出於sleep()中的線程也不會執行。因此sleep()方法常用來暫停線程執行。

前面有講到,當調用了新建的線程的start()方法後,線程進入到就緒狀態,可能會在接下來的某個時間獲取CPU時間片得以執行,如果希望這個新線程必然性的立即執行,直接調用原來線程的sleep(1)即可。

技術分享
 1 public class ThreadTest {
 2 
 3     public static void main(String[] args) {
 4 
 5         MyRunnable myRunnable = new MyRunnable();
 6         Thread thread = new Thread(myRunnable);
 7 
 8         for (int i = 0; i < 100; i++) {
 9             System.out.println(Thread.currentThread().getName() + " " + i);
10             if (i == 30) {
11                 thread.start();
12                 try {
13                     Thread.sleep(1);   // 使得thread必然能夠馬上得以執行
14                 } catch (InterruptedException e) {
15                     e.printStackTrace();
16                 }
17             }
18         }
19     }
20 }
21 
22 class MyRunnable implements Runnable {
23 
24     @Override
25     public void run() {
26         for (int i = 0; i < 100; i++) {
27             System.out.println(Thread.currentThread().getName() + " " + i);
28         }
29     }
30 }
技術分享

註:睡一個毫秒級夠了,因為CPU不會空閑,會切換到新建的線程。

3.後臺線程(Daemon Thread)

概念/目的:後臺線程主要是為其他線程(相對可以稱之為前臺線程)提供服務,或“守護線程”。如JVM中的垃圾回收線程。

生命周期:後臺線程的生命周期與前臺線程生命周期有一定關聯。主要體現在:當所有的前臺線程都進入死亡狀態時,後臺線程會自動死亡(其實這個也很好理解,因為後臺線程存在的目的在於為前臺線程服務的,既然所有的前臺線程都死亡了,那它自己還留著有什麽用...偉大啊 ! !)。

設置後臺線程:調用Thread對象的setDaemon(true)方法可以將指定的線程設置為後臺線程。

技術分享
 1 public class ThreadTest {
 2 
 3     public static void main(String[] args) {
 4         Thread myThread = new MyThread();
 5         for (int i = 0; i < 100; i++) {
 6             System.out.println("main thread i = " + i);
 7             if (i == 20) {
 8                 myThread.setDaemon(true);
 9                 myThread.start();
10             }
11         }
12     }
13 
14 }
15 
16 class MyThread extends Thread {
17 
18     public void run() {
19         for (int i = 0; i < 100; i++) {
20             System.out.println("i = " + i);
21             try {
22                 Thread.sleep(1);
23             } catch (InterruptedException e) {
24                 // TODO Auto-generated catch block
25                 e.printStackTrace();
26             }
27         }
28     }
29 }
技術分享

判斷線程是否是後臺線程:調用thread對象的isDeamon()方法。

註:main線程默認是前臺線程,前臺線程創建中創建的子線程默認是前臺線程,後臺線程中創建的線程默認是後臺線程。調用setDeamon(true)方法將前臺線程設置為後臺線程時,需要在start()方法調用之前。前天線程都死亡後,JVM通知後臺線程死亡,但從接收指令到作出響應,需要一定的時間。

4.改變線程的優先級/setPriority():

每個線程在執行時都具有一定的優先級,優先級高的線程具有較多的執行機會。每個線程默認的優先級都與創建它的線程的優先級相同。main線程默認具有普通優先級。

設置線程優先級:setPriority(int priorityLevel)。參數priorityLevel範圍在1-10之間,常用的有如下三個靜態常量值:

MAX_PRIORITY:10

MIN_PRIORITY:1

NORM_PRIORITY:5

獲取線程優先級:getPriority()。

註:具有較高線程優先級的線程對象僅表示此線程具有較多的執行機會,而非優先執行。

技術分享
 1 public class ThreadTest {
 2 
 3     public static void main(String[] args) {
 4         Thread myThread = new MyThread();
 5         for (int i = 0; i < 100; i++) {
 6             System.out.println("main thread i = " + i);
 7             if (i == 20) {
 8                 myThread.setPriority(Thread.MAX_PRIORITY);
 9                 myThread.start();
10             }
11         }
12     }
13 
14 }
15 
16 class MyThread extends Thread {
17 
18     public void run() {
19         for (int i = 0; i < 100; i++) {
20             System.out.println("i = " + i);
21         }
22     }
23 }
技術分享

5.線程讓步:yield()

上一篇博文中已經講到了yield()的基本作用,同時,yield()方法還與線程優先級有關,當某個線程調用yiled()方法從運行狀態轉換到就緒狀態後,CPU從就緒狀態線程隊列中只會選擇與該線程優先級相同或優先級更高的線程去執行。

技術分享
 1 public class ThreadTest {
 2 
 3     public static void main(String[] args) {
 4         Thread myThread1 = new MyThread1();
 5         Thread myThread2 = new MyThread2();
 6         myThread1.setPriority(Thread.MAX_PRIORITY);
 7         myThread2.setPriority(Thread.MIN_PRIORITY);
 8         for (int i = 0; i < 100; i++) {
 9             System.out.println("main thread i = " + i);
10             if (i == 20) {
11                 myThread1.start();
12                 myThread2.start();
13                 Thread.yield();
14             }
15         }
16     }
17 
18 }
19 
20 class MyThread1 extends Thread {
21 
22     public void run() {
23         for (int i = 0; i < 100; i++) {
24             System.out.println("myThread 1 --  i = " + i);
25         }
26     }
27 }
28 
29 class MyThread2 extends Thread {
30 
31     public void run() {
32         for (int i = 0; i < 100; i++) {
33             System.out.println("myThread 2 --  i = " + i);
34         }
35     }
36 }
技術分享

Java總結篇系列:Java多線程(二)