java 線程 Thread 使用介紹,包含wait(),notifyAll() 等函數使用介紹


(原創,轉載請說明出處!謝謝--http://www.cnblogs.com/linguanh/)

 

 此文目的為了幫助大家較全面、通俗地了解線程 Thread 相關基礎知識!

 

目錄:

       --線程的創建:

       --啟動線程

       --線程的調度

       --Thread 類的簡介

       --線程的同步/異步

       --wait() 和 notify(),notifyAll()方法

     

在講線程之前,先說下進程。

 

進程:是運行系統中,每個獨立運行的程序。例如win7,我既用酷狗軟件聽歌,又玩 LOL 游戲,又上QQ,那么這就有3個進程。

線程:一個進程里面有很多線程,進程是由線程組成的,線程的結束不一定會導致進程結束,而一個進程的結束,則會連帶它里面的所有線程被結束。

 

------------線程的創建:

創建->

        java 中有兩種方式:

        1,一種是通過實現Runnable 接口

        2,另一種是繼承線程類 Thread

實現Runnable接口的實例代碼:

1 class threadT implements Runnable{
2     @Override
3     public void run() {
4         //在這編輯要執行的代碼
5     }
6 }

上述代碼,通過實現 Runnable 的接口,重寫接口函數 run() 來實現新建一個線程。類比,點擊事件的接口 OnClickListener

 

實現:

1 Thread thread_test = new Thread(new threadT);
2  //實例化代碼一般放在主線程中,例如 main 中 或 onCreate()

 

繼承線程類Thread 的實例代碼:

1 class threadT1 extends Thread{
2         public void run(){
3          // edit your code
4         }
5  }

 

實現:

1 Thread thread_test = new ThreadT1();
thread_test.start();

 

上述兩種方法的比較:

      本人建議使用第一種,即使用實現Runnable 接口的方法來新建線程。

      原因:

            1:避免java 的單一 繼承帶來的局限;

            2:和 onClickListener 點擊事件一樣,當你有多個線程時,使用Runnable 再在run內用一個 switch 就能分開使用;

 

--------------啟動線程:

線程的啟動一般都是通過方法執行 statrt() 進行的。

 

完整 main 函數測試代碼:

 1 package com.LGH.ew;
 2 
 3 /**
 4  *  Created by Administrator on 2015/4/25.
 5  *  各線程,當主線程main 執行完了,它們還會繼續執行,彼此不影響
 6  *  多線程賣票 顯示 demo,by LinGuanHong
 7  */
 8 public class threadTest {
 9     public static void main(String[] args){
10         threadT t1 = new threadT1();//線程 1
11         Thread t2 = new Thread(new ThreadT());//線程 2
12        
13         t2.start();
14         t1.start();
15     }
16 }

 

------------線程的調度:

調度是什么意思呢?就是 cpu 執行每個線程的順序,注意,不一定是按順序的,這個和線程的優先級有關!

線程的調用是統一由JVM根據時間片來調度的,其執行順序隨機。大致執行流程如下:

 

 

由上述可以看出, jvm 在執行多線程 程序的時候,在某一個時間段,其實也是只能運行一個線程,

但是它用划分時間片段的機制來轉換調用各個線程,這個時間片段很短!

 

-----------Thread 類的簡介

 

java.lang.Thread 類:

    常用的方法有:

    ---public void start(); 啟動該線程,其中調用了這個方法不一定就立即進行,還要看是否被調度到;

    ---public static Thread currentThread(); 靜態方法,這個方法很重要,用來返回當前正在執行的線程對象引用;

    ---public final booleann isAlive();測試線程是否還活着;

    ---public Thread.State getState();返回該線程當前的狀態,

                 分別有:

                          NEW 實例化了,但尚未啟動的線程是這種狀態,新建 態;

                          RUNNABLE 正在被執行的狀態;

                          BLOCKED 受阻塞並等待某個監視器鎖的線程態;

                          WAITING 無限期地等待另外一個線程來執行特地操作,等待 態;

                          TIMED_WAITING 等待另一個線程來執行取決於指定等待時間的操作,超時等待 態

                          TERMINATED 已退出的線程的狀態,終止 態。

     ---public final String getName();返回線程名稱,一般和setName(),連用;

     ---public final void setDaemon(boolean on);將該線程標記為守護線程;

     ---public static void sleep(long millis);在指定的毫秒內,讓該線程暫停;

     ---public final void setPriority(int level);設置線程的優先級,可以是 1,5,10,分別是 低、普通、最高,默認是 5 ;

     ---public static void yield();線程讓步,它會暫停該線程,把執行的機會讓給相同或優先級更高的線程;

     ---public void final join();把某線程加入到某線程中去,被加者變為子線程;

     ---public void interrupt(); 中斷線程.

 

------------線程的生命周期

 

其生命周期可以總結為上面的 6個 狀態,圖解如下:

 

-------------線程的同步/異步

下面通過demo 代碼說明,內涵 synchronized 保護機制

 

  1 package com.LGH.ew;
  2 
  3 /**
  4  *  Created by Administrator on 2015/4/25.
  5  *  各線程,當主線程main 執行完了,它們還會繼續執行,彼此不影響
  6  *  多線程賣票 顯示 demo,by LinGuanHong
  7  */
  8 public class threadTest { //賣火車票例子
  9     public static void main(String[] args){
 10         threadT T = new threadT();
 11         Thread t1 = new Thread(T);//線程 1
 12         t1.setName("1");// 設置 線程名字
 13         //t1.getState(); 這里有具體的線程對象,所以可以直接使用其類方法;
 14         t1.start();
 15         Thread t2 = new Thread(T);//線程 2
 16         t2.setName("2");
 17         t2.start();
 18         Thread t3 = new Thread(T);//線程 3
 19         t3.setName("3");
 20         t3.start();
 21         Thread t4 = new Thread(T);//線程 4
 22         t4.setName("4");
 23         t4.start();
 24         Thread t5 = new Thread(T);//線程 5
 25         t5.setName("5");
 26         t5.start();
 27     }
 28 }
 29 class threadT implements Runnable{ //實例化接口 
 30     private int tickets = 0;
 31     @Override
 32     public void run() {
 33         boolean control = true;
 34         while(control){
 35             control = sell();//調用sell 方法,大家可以通過改變這個函數的調用,來看異步、同步的效果
 36         }
 37     }
 38 
 39     public boolean sell(){//異步線程機制,會被打斷,所謂打斷,就是會出現 線程1 賣了第2張票時,線程3也賣了第2 張
 40         boolean control = true ;
 41         if(tickets<100){
 42             tickets ++;
 43             //在函數內,如果沒有具體的線程對象,就要使用靜態方法 currentThread() 返回當前正在執行的線程對象的引用,在使用類方法
 44             System.out.println(Thread.currentThread().getName()+":"+tickets);//同上
 45             Thread.State state = Thread.currentThread().getState();//同上
 46             System.out.println("State:"+state.toString());//輸出當前的狀態,正常是 runnable
 47         }else{
 48             control = false;
 49         }
 50         try{
 51             Thread.sleep(1);
 52         }catch (Exception e){
 53             e.printStackTrace();
 54         }
 55         return control;
 56     }
 57 
 58     //關鍵字 - synchronized 保護 當前 函數在執行時不被其他線程打斷,同步線程機制
 59     //整體同步,效率低
 60     public synchronized boolean sell1(){ 
 61         boolean control = true ;
 62         if(tickets<100){
 63             tickets ++;
 64             //在函數內,如果沒有具體的線程對象,就要使用靜態方法 currentThread() 返回當前正在執行的線程對象的引用,在使用類方法
 65             System.out.println(Thread.currentThread().getName()+":"+tickets);//同上
 66             Thread.State state = Thread.currentThread().getState();//同上
 67            // System.out.println("State:"+state.toString());
 68         }else{
 69             control = false;
 70         }
 71         try{
 72             Thread.sleep(1);
 73         }catch (Exception e){
 74             e.printStackTrace();
 75         }
 76         return control;
 77     }
 78     //關鍵字 - synchronized 實質是一個對象鎖
 79 
 80     public boolean sell2(){ // 條件 關鍵字 - synchronized 保護 當前 函數在執行時不被其他線程打斷,同步線程機制
 81         boolean control = true ;
 82         synchronized(this) { //僅僅同步會操作到的共同部分變量,tickets,這樣避免同步整體,提高效率
 83             if (tickets < 100) {
 84                 tickets++;
 85                 //在函數內,如果沒有具體的線程對象,就要使用靜態方法 currentThread() 返回當前正在執行的線程對象的引用,在使用類方法
 86                 System.out.println(Thread.currentThread().getName() + ":" + tickets);//同上
 87                 Thread.State state = Thread.currentThread().getState();//同上
 88                 // System.out.println("State:"+state.toString());
 89             } else {
 90                 control = false;
 91             }
 92         }
 93         try{
 94             Thread.sleep(1);
 95         }catch (Exception e){
 96             e.printStackTrace();
 97         }
 98         return control;
 99     }
100 }

 

-------------wait() 和 notify(),notifyAll()方法

他們是同步機制中的重要部分,必須和 synchronized 關鍵字結合使用,即在 synchronized 代碼塊中使用!

否在 拋出 Illegal..... 非法異常。

wait() 被調用,當前線程將會被中斷運行,並且放棄該對象的鎖;

執行了 notify() 后,會喚醒此對象等待池中的某個線程,使之成為可運行的線程;

notifyAll()則喚醒所有;

 

下面用一個具體的demo 說明:

前言-------------

     生產者和消費者的問題,生產者將產品交給店員,而消費者從店員處取走產品,店員一次只能持有固定的產品,如果生產者生產過多了的產品,店員會叫生產者等一下,如果店中有空位放產品了再通知生產者繼續生產;

     如果店中供不應求,店員會叫消費者等一會,等生產者生產了再叫消費者來拿。

問題:

      生產者生產過快,消費者會漏掉一些,沒取到;

      消費者比生產者快,消費者會拿到相同的;

 

 1 package com.LGH.ew.view;
 2 
 3 /**
 4  * Created by Administrator on 2015/4/25.
 5  */
 6 public class Product { //生產者、消費者問題
 7     public static void main(String[] args){
 8         clerk c = new clerk();
 9         Thread productT = new Thread(new Producer(c));//生產者線程
10         Thread consumerT = new Thread(new Consumer(c));//消費者線程
11         productT.start();
12         consumerT.start();
13     }
14 }
15 class clerk{ //店員
16     private int product = 0; //默認 0 個產品
17     public synchronized void addproduct(){ //生產出的產品,交給店員
18         if(this.product>=20){
19             try{
20                 wait(); //產品過多,稍后再生產
21             }catch (Exception e){
22                 e.printStackTrace();
23             }
24         }else{
25             product++;
26             System.out.println("生產者生產第"+product+"個產品。");
27             notifyAll(); //通知等待區的消費者可取產品
28         }
29     }
30     public synchronized void getproduct(){ //消費者從店員處取產品
31         if(this.product<=0){
32             try{
33                 wait(); //缺貨,稍后再取
34             }catch (Exception e){
35                 e.printStackTrace();
36             }
37         }else{
38             System.out.println("消費者取走了第:" + product + "產品。");
39             product--;
40             notifyAll(); //通知等待取得生產者可以繼續生產
41         }
42     }
43 }
44 
45 class Producer implements Runnable{ //生產者線程
46 
47     private clerk c;
48     public Producer(clerk c){
49         this.c = c;
50     }
51     @Override
52     public void run() {
53         System.out.println("生產者開始生產產品。");
54         while(true){
55             try{
56                 Thread.sleep((int)(Math.random()*10)*100);
57             }catch(Exception e){
58                 e.printStackTrace();
59             }
60             c.addproduct(); //生產
61         }
62     }
63 }
64 
65 class Consumer implements Runnable{ //消費者線程
66 
67     private clerk c ;
68 
69     public Consumer(clerk c){
70         this.c = c;
71     }
72     @Override
73     public void run() {
74         System.out.println("消費者開始取走產品。");
75         while(true){
76             try{
77                 Thread.sleep((int)(Math.random()*10)*100);
78             }catch(Exception e){
79                 e.printStackTrace();
80             }
81             c.getproduct(); //取產品
82         }
83     }
84 }

 

全文終,各位如果覺得還可以的話,請幫忙點個贊,讓更多人能看到。謝謝

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM