(原創,轉載請說明出處!謝謝--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 }
全文終,各位如果覺得還可以的話,請幫忙點個贊,讓更多人能看到。謝謝