Java多線程
1、多線程概述
當一個程序運行時,內部可能包含了多個順序執行流,每個順序執行流就是一個線程。主要以下幾個優點:
- 線程之間很容易實現共享內存
- 創建線程代價較小
- Java語言內置多線程功能支持 </ul>
- 采用實現Runnable接口方式的線程還可以繼承其他類,而繼承Tread類后不能再繼承其他父類。
- 實現Runnable接口方式的線程可以共享一個target對象,適合多個相同線程來處理同一份資源的情況
- 若需要訪問當前線程,實現Runnable接口方式只能使用Thread.currentThread()方法,而繼承Thread可直接使用this即獲取當前線程。
- 調用Executors類的靜態工廠方法創建一個ExecutorService對象,該對象代表一個線程池。
- 創建Runnable實現類或Callable實現類的實例,作為線程執行任務。
- 調用ExecutorService對象的submit方法提交Runnable實例或Callable實例。
- 當不想提交任何任務時調用ExecutorService對象的shutdown方法來關閉線程池。
2、線程的創建和啟動
所有的線程對象都是Thread類或其子類的對象,每一個線程完成一定的任務。
Java定義了兩種創建線程的方法:
方法一:繼承Thread類創建線程類
? 定義Thread的子類,并重寫run方法
? 創建Thread子類的實例,即創建了線程對象
? 用線程對象的start方法來啟動該線程
public class DemoThread extends Thread { private int i; String name; public DemoThread(String name) { super(name); } public void run() { for(;i<100;i++) System.out.println(Thread.currentThread().getName()+"-------"+i); } public static void main(String[] args) { for(int i=0;i<100;i++) { System.out.println(Thread.currentThread().getName()+"-----------"+i); if(i==20) { new DemoThread("windows1").start(); new DemoThread("windows2").start(); } } } }
? 定義Runnable接口的實現類,并重寫該接口的run方法(該方法是該線程的線程執行體)
? 創建Runnable實現類的實例,并以此實例作為Thread的target來創建Tread對象
public class DemoThread implements Runnable { private int i; public void run() { for(;i<100;i++) System.out.println(Thread.currentThread().getName()+"-------"+i); } public static void main(String[] args) { for(int i=0;i<100;i++) { System.out.println(Thread.currentThread().getName()+"-----------"+i); if(i==20) { DemoThread t=new DemoThread(); new Thread(t,"Windows1").start(); new Thread(t,"Windows2").start(); } } } }
兩種方法比較:
3、線程的生命周期
線程被創建并啟動以后要經歷五種狀態,分別是新建(New)、就緒(Runnable)、運行(Running)、阻塞(Blocked)和死亡(Dead)。
新建:使用關鍵字new創建一個線程后,處于新建狀態,此時僅由虛擬機為其分配內存并初始化成員變量,程序不會執行線程執行體。 就緒:當線程對象調用start()方法后,該線程處于就緒狀態,虛擬機為其創建調用棧和程序計數器,但是此時線程并沒有運行,只是表示線程可以運行了。
運行:當處于就緒狀態的線程獲得了CPU,開始執行run方法,則該線程處于運行狀態。
阻塞:當發生線程調用sleep方法、阻塞式IO方法、suspend方法、等待通知(notify),線程將近阻塞狀態。阻塞狀態在合適的時候會重新進入就緒狀態。
死亡:線程會以以下三種方式結束,然后就處于死亡狀態,run方法執行完成、線程拋出未捕獲的異常、直接跳躍stop方法結束進程。
4、線程的控制
isAlive():測試線程是否處于活動狀態
isDaemo():測試進程是否為守護進程
join():等待該進程終止
sleep():在指定的毫秒數內讓正在執行的線程休眠,該線程不丟失任何監視器的所屬權
yield():暫停當前正在執行的線程對象,并執行其他線程,它是將線程轉入就緒狀態
setPriority(int newPriority):更改線程的優先級
5、線程的同步
當兩個或多個線程需要訪問同一共享資源時,需要某種方式來確保資源在某一時刻只被一個線程使用,這個方式稱為“同步“。
為了解決同步問題,java引入同步監視器,代碼塊格式如下:
synchronized (obj) { }
同步鎖:它具有與使用 synchronized 方法和語句所訪問的隱式監視器鎖相同的一些基本行為和語義,但功能更強大。 使用Lock對象的代碼格式如下:
public class X { private final ReentrantLock lock=new ReentrantLock(); public void m() { lock.lock();//加鎖 try { //需要保證線程安全的代碼 } finally { lock.unlock();//釋放鎖 } } }
Java為了避免輪詢檢測,通過wait()、notify()和notifyAll()方法實現進程內通信的機制。
wait():告訴調用線程放棄監控器進入等待模式直到其他線程進入同一監控器并調用notify()方法。
wait():告訴調用線程放棄監控器進入等待模式直到其他線程進入同一監控器并調用notify()方法。
notify():喚醒在此同步器上等待的單個線程
notifyAll():喚醒在此同步器上等待的所有線程
7、線程池
線程池在系統啟動時就創建大量空閑的線程,程序將一個Runnable對象傳給線程池,線程池就會啟動一個線程來執行該對象的run方法,當run方法執行結束后該線程不會死亡,而是再次返回線程池中稱為空閑狀態的,等待執行下一個Runnable對象的run方法。
使用線程池來執行線程任務的步驟如下:
eg:
class TestThread implements Runnable { public void run() { for(int i=0;i<50;i++) { System.out.println(Thread.currentThread().getName()+"---"+i); } } } public class TestMain { public static void main(String[] args) { // TODO 自動生成的方法存根 TestThread t=new TestThread(); ExecutorService pool=Executors.newFixedThreadPool(6); pool.submit(new Thread(t)); pool.submit(new Thread(t)); pool.shutdown(); } }
來自:http://www.cnblogs.com/xujian2014/p/4431350.html
本文由用戶 fdwm 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!