CoreJava學習10——多線程

多線程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。

相關文章
相關標籤/搜索