多線程java
Java的特色之一就是線程的處理較爲簡單。安全
通常操做系統都支持同時運行多個任務,一個任務一般就是一個程序,每一個運行中的程序被稱爲一個進程,每一個順序執行流就是一個線程。多線程
進程:正在運行的程序,是程序動態的執行過程(運行內存中)。併發
線程:在進程內部,併發運行的過程。對於一個程序而言,可能同時運行多個任務,那麼每一個任務稱爲一個線程。app
併發:進程是併發運行的,OS將時間劃分爲不少時間片斷(時間片),儘量均勻分配給正在運行的程序,微觀上進程走走停停,宏觀上都在運行,這種都運行的現象叫併發,可是不是絕對意義上的「同時發生」。異步
一、Thread類ide
Thread類表明線程類型。函數
咱們調用start()方法時候,該線程會想線程調度註冊當前線程。只有註冊了,纔有機會被分配時間片進行併發運行。高併發
不能調用run方法,若是調用了,就不是併發運行了,就變成同步了。有前後順序執行。ui
時間片是不均勻的,每一個線程分配時間不是相等的。線程調度機制儘量均勻的將時間片斷分配給不一樣線程,讓他們都有機會的到cpu的運行。分配給誰的時間片斷是不可控的。
stop()方法,關閉線程,因爲具備不安全性,不建議使用。
正常的線程中止方法是讓run()方法正常的執行完畢。
線程運行過程當中,若出現該類未捕獲異常,該線程馬上終止。可是不會影響當前進程中其餘線程的工做。
若當前進程中全部線程都終止了,那麼進程終止。
建立線程的另外一種方式將線程與線程體分開,做爲線程體就是線程要併發執行的邏輯。最好的模式應該是線程只關心併發操做,不關心具體併發作的事情,咱們應該將線程與線程體自己解耦。
例子:
public static void main(String[] args) { /** * Thread 類 * Thread類的一個實例表明一個線程 * 咱們能夠經過繼承Thread並重寫run方法,來完成咱們想併發的代碼。 */ Thread thread1 = new NumThread(); Thread thread2 = new HelloWordThread(); /** * 不能調用run方法, */ thread1.start(); thread2.start(); } /** * 建立一個併發任務 * 重寫run方法來編寫併發任務代碼。 */ public static class NumThread extends Thread{ @Override public void run() { for (int i = 0; i < 10000; i++) { System.out.println(i); } }
二、Runnable實現線程
建立一個實現Runnable接口,重寫run方法,以實現了Runnable接口的類的實例對象做爲建立Thread類對象的構造函數的參數。
public static void main(String[] args) { //建立要併發執行的邏輯再交給線程去 Thread th = new Thread(new HooThread()); th.start(); } public static class HooThread implements Runnable{ public void run(){ for (int i = 0; i < 10000; i++) { System.out.println("how are you"); } } }
可是這裏經常使用內部類。
new Thread(new Runnable(){
public void run(){...}
}).start();
這種方式將線程體和線程分離開,咱們就能夠最大程度的利用線程,有了這個思想,就有了後面的線程池的應用。
三、線程的生命週期
線程一旦結束,不能再次調用start()方法。、
相關方法:
static void yield()當前現橫讓出處理器(離開Running狀態),使當前線程進入Runnable狀態等待,等待下次分配時間片。
static void sleep(times)讓線程從Running狀態進入block狀態,阻塞times好秒後自動回到Runnable狀態。
若是在block時,其餘線程打斷當前線程的Block(sleep)就會發生異常InterruptedException.
void interrupt()中斷線程。
final void setPriority(int)改變線程的優先級。
final void join()等待該線程終止。
/** * 電子錶功能 * 思路: * 1.獲取系統時間 * 2.每秒輸出一次 */ SimpleDateFormat format=new SimpleDateFormat("hh:mm:ss"); while(true){ Date date = new Date(); String s = format.format(date); System.out.println(s); Thread.sleep(1000); }
一個例子:模擬一個節目的砸牆
public static void main(String[] args) { /** * 砸牆 * t1線程:林永健 處理睡眠阻塞的線程 * t2線程:黃宏 用於打斷t1睡眠阻塞的線程 */ final Thread lin = new Thread(){ public void run() { System.out.println("林:睡覺去了"); try { Thread.sleep(10000000); } catch (InterruptedException e) { //e.printStackTrace(); System.out.println("林:幹嗎呢?都破了相了!"); } } }; lin.start(); Thread hang = new Thread(){ public void run() { System.out.println("黃:準備砸牆!"); for (int i = 9; i >0; i--) { System.out.println("黃:"+(10*i)); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("黃:搞定!"); /** * 打斷t1的睡眠阻塞 */ lin.interrupt();//中斷線程 } }; hang.start(); }
四、線程的優先級
線程的優先級根據數字劃分爲10個等級。
1最小 對應的常量是 MIN_PRIORIITY
10最大 對應的常量是 MAX_PRIORIITY
默認是5 對應的常量是 NORM_PRIORIITY
//設置優先級
t1.setPriority(Thread.MAX_PRIORITY);
t2.setPriority(1);
不是絕對的,但大多狀況是這樣,畢竟線程分配調度的時間片不可控。
五、守護線程
又叫後臺線程,特色:當進程中全部前臺線程都終止後,守護線程強制終止。
當進程中只有守護線程時,Java虛擬機退出,進程也終止了。
後臺線程是在線程啓動前經過方法設置的。
setDaemo(boolean) 當參數是true時,該線程是後臺線程。必須在線程啓動以前設置,不然沒有用了。
//守護線程,要在start以前設置。
jack.setDaemon(true);
六、線程同步的概念
線程同步,能夠理解爲線程A和B是一塊配合,A執行到必定程度時要依靠B的某個結果,因而停下來,示意B執行;B依言執行,在將結果給A;A再繼續操做。
所謂同步,就是在發出一個功能調用時,在沒有獲得結果以前,該調用就不返回,同時其它線程也不能調用這個方法。
1)異步 併發,各幹本身的。
2)同步 步調一致的處理,多個線程不能同時訪問。
這裏就引起出一個關鍵字 Synchronized
多線程併發讀寫同一個臨界資源時發生「線程併發安全問題」
可使用同步代碼快解決線程併發安全問題。
synchronized(同步監視器){}
能夠修飾一個方法也能夠以獨立的代碼快存在。
同步監視器:是一個任意對象實例,是一個多個線程之間的互斥的鎖機制,多個線程要使用同一個「監視器」對象實現同步互斥。
常見的寫法:synchronized(this){} 儘可能減小同步範圍,提升併發效率。
synchronized修飾的方法,當一個線程進入到該方法後,會對當前方法所屬的對象枷鎖。其它線程在訪問這個方法時候,發現被鎖上了,就在方法外等待,直到對象上的鎖被釋放爲止。
七、線程安全類與線程不安全類
StringBuffer是同步的 synchronized append();
StringBuilder不是同步的 append();
Vector/HashTable是同步的。
ArrayList/HashMap不是同步的。
若是把一個不是同不的集合變成同步的集,可使用
Collections.synchronizedList();
Collections.synchronizedMap();
具體例子以下:
ArrayList list = new ArrayList();
List syncList = Collections.synchronizedList(list);
這樣就獲得線程安全的集合
也能夠直接用
Collections.synchronizedList();
Collections.synchronizedMap();
Collections.synchronizedSet();
獲得線程安全的集合。
八、wait和notify簡介
屬於Object中的方法,用於多線程之間須要協同工做(等待和喚醒)。
就是說:若是條件不知足時,則等待。當條件知足時,等待該條件的線程將被喚醒。在Java中,這個本身的實現依賴於wait/notify.等待機制與鎖的機制是密切關聯的。
當線程A調用了B對象的wait方法,那麼該線程就在B對象上等待。A線程就進入了wait阻塞。若是線程C也調用了B的wait方法,那麼該線程也在B對象上等待。當B調用了notify方法,那個A或者B隨機一個進入了Runnable狀態開始運行,另外一個任然處於wait阻塞。
notifyAll()方法可讓等待的全部線程進入Runnable。