天天看點

好程式員大資料學習路線分享大資料之線程

  好程式員大資料學習路線分享大資料之線程,預設情況下,主線程和垃圾回收線程都是由系統建立的,但是我們需要完成自己的功能----建立自己的線程對象

 java将線程面向對象了,形成的類就是Thread,在Thread類内部執行任務的方法叫run()

 注意:如果想讓run作為任務區,必須讓他去被自動調用.我們通過執行start()方法,來開啟線程,繼而實作run方法的自動調用.

主線程的名字:main   子線程的名字:從Thread-0開始命名

//建立自己的線程對象

//分析:由于我們實作的實際功能Thread類是決定不了的,是以沒有辦法将我們的功能放入Thread的run方法裡,如果我們想實作自己的功能,可以寫Thread類的子類,重寫run方法,實作我們的功能.run就是我們的任務區

實作多線程的方式兩種:

 第一種方式:通過建立Thread子類的方式實作功能----線程與任務綁定在了一起,操作不友善

 第二種:将任務從線程中分離出來,哪個線程需要工作,就将任務交給誰,操作友善

當線程與任務分離後

這裡Thread内部預設有一個run,又通過ticket傳入一個run,為什麼優先調用的是傳入的run

如果該線程是使用獨立的 Runnable 運作對象構造的,則調用該 Runnable 對象的 run 方法;否則,該方法不執行任何操作并傳回。

2.線程安全

1、synchronized關鍵字:

1、synchronized關鍵字的作用域有二種:

1)是某個對象執行個體内,synchronized aMethod(){}可以防止多個線程同時通路這個對象的synchronized方法(如果一個對象有多個synchronized方法,隻要一個線程通路了其中的一個synchronized方法,其它線程不能同時通路這個對象中任何一個synchronized方法)。這時,不同的對象執行個體的synchronized方法是不相幹擾的。也就是說,其它線程照樣可以同時通路相同類的另一個對象執行個體中的synchronized方法;

2)是某個類的範圍,synchronized static aStaticMethod{}防止多個線程同時通路這個類中的synchronized static 方法。它可以對類的所有對象執行個體起作用。

2、除了方法前用synchronized關鍵字,synchronized關鍵字還可以用于方法中的某個區塊中,表示隻對這個區塊的資源實行互斥通路。用法是: synchronized(this){/區塊/},它的作用域是目前對象;

3、synchronized關鍵字是不能繼承的,也就是說,基類的方法synchronized f(){} 在繼承類中并不自動是synchronized f(){},而是變成了f(){}。繼承類需要你顯式的指定它的某個方法為synchronized方法;

實作線程安全的方式:

1.在代碼中使用同步代碼塊兒(同步鎖)

解釋:在某一段任務中,同一時間隻允許一個線程執行任務,其他的線程即使搶到了cpu,也無法進入目前的任務區間,隻有當目前的線程将任務執行完後,其他的線程才能有資格進入

同步代碼塊兒的構成:

synchronized(鎖(對象)){

  同步的代碼

 }

對作為鎖的對象的要求:

1.必須是對象      

2.必須保證被多個線程共享

可以充當鎖的:

1.一個普通的對象      

2.目前對象的引用--this    

3.類的位元組碼檔案 --注意:位元組碼檔案的使用範圍太大,一般不建議使用.

同步代碼塊兒的特點:

1.可以保證線程的安全    

2.由于每次都要進行判斷處理,是以降低了執行效率

總結:什麼時候使用同步代碼塊兒

1.多個線程共享一個資料

2.至少有兩個線程

比較同步代碼塊兒和同步函數

同步代碼塊兒使用更加的靈活,隻給需要同步的部分代碼同步即可,而同步函數是給這個函數内的所有代碼同步.

由于處于同步的代碼越少越好,是以最好使用同步代碼塊兒

注意:1.當在一個類中同時存在多個synchronized修飾的代碼塊兒或函數時,要想安全,就必須讓他們後面的對象一緻。因為隻有同一把鎖才能安全。

同步函數的鎖:this

2靜态同步函數在進記憶體的時候不會建立對象,但是存在其所屬類的位元組碼檔案對象,屬于class類型的對象,

是以靜态同步函數的鎖是其所屬類的位元組碼檔案對象

示例:

    //使用同步代碼塊兒

    public void addMoney(int money) {

        synchronized (Bank.class) {

            this.money += money;

            System.out.println(this.money);

        }

    }

    //使用同步函數

    //非靜态的同步函數

    //在synchronized後面預設有一個this

    public synchronized void addMoney(int money) {

        this.money += money;

        System.out.println(this.money);

    }

 wait():讓目前的線程變成等待的狀态,放入一個池子(線程容器),失去了搶cpu的能力,.等待喚醒(鎖相當于給目前的線程做了一個标記)

notify():讓目前的線程從等待狀态喚醒,相當于從池子中取出線程.(喚醒的是同一把鎖下的任意一個線程)

notifyAll():喚醒的是同一把鎖下的所有線程

死鎖:出現的情況有兩種

 1.所有的線程處于等待狀态

 2.鎖之間進行嵌套調用

2.Lock

比較synchronized和Lock

 1.synchronized:從jdk1.0就開始使用的同步方法-稱為隐式同步

 synchronized(鎖對象){//擷取鎖      我們将鎖還可以稱為鎖旗艦或者監聽器

 同步的代碼

 }//釋放鎖

 2.Lock:從jdk1.5開始使用的同步方法-稱為顯示同步

 原理:Lock本身是接口,要通過他的子類建立對象幹活兒

 使用過程:

 首先調用lock()方法擷取鎖

 進行同步的代碼塊兒

 使用unlock()方法釋放鎖

 使用的場景:

 當進行多生産者多消費者的功能時,使用Lock,其他的都使用synchronized

 使用效率上:Lock高于synchronized

線程的停止: 3種

 1.通過一個辨別結束線程

 2.調用stop方法---因為有固有的安全問題,是以系統不建議使用.

 3.調用interrupt方法----如果目标線程等待很長時間(例如基于一個條件變量),則應使用 interrupt 方法來中斷該等待。

守護線程:

相當于背景線程.依賴于前台線程.正常情況下,目前台線程結束的時候,不管守護線程有沒有結束,都會立刻結束.

 典型的守護線程:垃圾回收線程

 當程式調用setDaemon方法時,并且将參數設定成true.目前線程就變成了守護線層.

 注意:這個方法一定要在start方法之前調用

 thread0.setDaemon(true);

 thread0.start();

join()方法:

 原理:線程一旦調用了join方法,他的優先級會高于主線程.主線程會等目前的線程執行完後再去執行.

 注意點:優先級隻比main線程的高.對其他的線程沒有影響.

 當線程開始工作後,讓t0調用join方法,讓他的優先級高于main線程

 注意:join方法必須線上程開始工作後,執行.

t0.start();

      try {

          t0.join();

      } catch (InterruptedException e) {

            // TODO Auto-generated catch block

            e.printStackTrace();

        }      

wait():使一個線程處于等待狀态,并且釋放所持有的對象的lock。

sleep():使一個正在運作的線程處于睡眠狀态,是一個靜态方法,調用此方法要捕捉InterruptedException異常。

notify():喚醒一個處于等待狀态的線程,注意的是在調用此方法的時候,并不能确切的喚醒某一個等待狀态的線程,而是由JVM确定喚醒哪個線程,而且不是按優先級。

notityAll():喚醒所有處入等待狀态的線程,注意并不是給所有喚醒線程一個對象的鎖,而是讓它們競争。

繼續閱讀