Thread知識

weixin_33797791發表於2018-03-28

1.基礎知識

1.sleep()的作用是在指定的毫秒數內讓當前"正在執行的執行緒"休眠.
2.getId()獲取執行緒的唯一標識
3.停止執行緒3種方法

- 使用退出標誌,正常退出
- 使用stop強行終止執行緒,已廢棄.(他會丟擲一個ThreadDeath異常.不需要捕獲)
- 使用interrupt中斷執行緒,他不會立即停止執行緒,而是加一個停止的標記.(線上程中捕獲這個標記.進行主動退出)
- 使用丟擲異常.try-catch停止執行緒

4.靜態方法 interrupted()返回當前正在執行的執行緒是否已經中斷.,在哪個執行緒裡調就返回哪個執行緒的中斷狀態
執行緒的方法 isInterrupted()返回撥用執行緒是否已經中斷,哪個執行緒物件呼叫他,他返回哪個執行緒的中斷狀態.
5.suspend()方法暫定執行緒 resume()方法恢復執行緒,缺點是會佔有公共物件的鎖和資料不同步
6.yield()使當前執行緒放棄當前的CPU資源,但放棄時間不確定,有可能剛放棄馬上又獲得CPU時間片.
7.執行緒優先順序 1-10 , 10最高.優先順序高得到的CPU資源較多.但不是絕對的.優先順序具有繼承性,如A執行緒啟動B執行緒.則B執行緒的優先順序和A相同.
8.守護執行緒,是特殊的執行緒.當程式中不存在非守護執行緒時,守護執行緒自動銷燬. gc就是守護執行緒.
9.synchronized 關鍵字取得的就是物件鎖.而一個物件只有一把鎖.當一個執行緒獲得一個物件的鎖後.可以直接訪問他所有的帶鎖的方法.稱為鎖的重入機制.可重入鎖也支援父子類繼承的環境中.既子類拿到物件鎖後.可以訪問父類的帶鎖的方法.
10.一個執行緒執行的程式碼出現異常時,其所持有的鎖會自動釋放.
11.鎖不能被繼承.既父類的同步方法加了鎖.在子類重寫後卻沒加鎖,那麼子類方法不會繼承父類的鎖.因為鎖是針對物件的.建立子類物件時不會建立父類物件.也就不涉及父類物件的鎖的方法.
12.同步程式碼快.可以減少同步等待的時間.不再同步程式碼塊中的程式碼是非同步執行,同步程式碼塊中的程式碼同步執行.同步程式碼塊也是鎖定某個物件的.
13.synchronized關鍵字加到static方法上是給Class類上鎖,而synchronized關鍵字加到非static靜態方法上是給物件加鎖.而String具有常量池.不建議對String 加鎖.
14.volatile關鍵字.使變數在多個執行緒間可見.

5423393-fb2afa181fc20976.png
1.png

  • volatile關鍵字強制從公共記憶體中讀取變數的值.而不使用每個執行緒的工作記憶體.
  • volatile增加了例項變數在多個執行緒之間的可見性
  • volatile是執行緒同步的輕量級實現,效率比synchronized高並且volatile只能修飾變數
  • 多執行緒訪問volatile不會傳送阻塞,而訪問synchronized會出現阻塞
  • volatile能保證資料的可見性,但不保證原子性(原子性:即一個操作或者多個操作 要麼全部執行並且執行的過程不會被任何因素打斷,要麼就都不執行)而synchronized可保證原子性,繼而保證可見性
  • volatile解決的是變數在多個執行緒的可見性,synchronized解決的是多個執行緒訪問資源的同步性(個人理解volatile用來讀值比較好.寫的話會資料錯亂,並不能保證同步性.)
    15.wait/notify方法在呼叫前執行緒必須持有物件鎖,這兩個方法屬於object.wait呼叫後會釋放鎖.notify方法執行後,當前執行緒要把同步方法執行完才會釋放鎖.之後wait的執行緒被喚醒,拿到物件鎖.如果某執行緒wait後沒有其他執行緒呼叫notify.則這個執行緒會一直等待下去.即時物件鎖已經被釋放. notifyAll喚醒全部wait的執行緒.
    16 執行完同步程式碼塊會釋放鎖.執行同步程式碼塊過程中如果遇到異常終止,會釋放鎖.執行鎖物件的wait方法會釋放鎖.notify方法一次會隨機喚醒一個wait方法.
    17.通過管道進行執行緒間通訊,可以通過位元組流,字元流.
    pipeStream (管道流)用於在不同執行緒間直接傳送資料,一個執行緒傳送資料到管道,另一個執行緒從管道中讀取資料.
    18.join的作用是等待執行緒物件銷燬.Z執行緒中呼叫X.join使所屬執行緒物件X正常執run()方法,而使當前執行緒Z進行無限期的阻塞,等待執行緒X銷燬後在繼續執行Z後面的程式碼.
    join在內部是使用wait方法實現,所以會釋放鎖.而sleep不會釋放鎖.
    join過程中呼叫interrupt會丟擲異常.
    19.threadLocal可以為每個執行緒單獨設定自己的值.inheritableThreadLocal可以讓子執行緒從父執行緒中取得父執行緒繼承下來的值.
    20.ReentrantLock類,用來實現同步功能,支援獲得鎖,釋放鎖.
lock.lock() 獲得鎖  lock.unlock() 釋放鎖
Condition 是在一個Lock物件裡面建立多個Condition(物件監視器)例項,執行緒物件可以註冊在指定的Condition中,從而可以有選擇性的進行執行緒通知
在排程上更加靈活.既可以喚醒指定執行緒
Condition的wait,sign方法需要在Lock.lock後呼叫.
公平鎖.執行緒獲取鎖的順序是根據執行緒枷鎖的順序來分配的,非公平鎖,執行緒獲得鎖是隨機的.ReentrantLock建構函式可以傳boolean表示公平鎖還是非公平鎖
getHoleCount()返回當前執行緒保持次鎖定的個數,也就是呼叫lock方法的次數.
getQueueLength() 返回等待獲取鎖的執行緒的個數.
getWaitQueueLength(Condition condi) 返回等待condition的wait的執行緒數. 
tryLock() 僅在鎖未被另一個執行緒保持時,才獲取該鎖.
awaitUntil(mills) 在等待mills的到期時間前可以被喚醒.不必非要等待mills長的時間

21.ReenTrantReadWriteLock讀寫鎖
讀寫鎖分為兩個鎖.讀鎖,稱為共享鎖. 寫鎖,稱為排它鎖.多個寫鎖或者多個讀鎖加寫鎖互斥.既可以多執行緒讀.只能單執行緒寫.
22.單例模式與多執行緒結合
1.惡漢模式,靜態變數直接建立物件.然後返回
2.懶漢模式.在呼叫時返回.正規寫法是雙檢查機制

5423393-985935b3ba64f823.png
1.png

3.私有的靜態內部類建立外部類物件.提供方法返回外部類物件.

5423393-951d86da1642f9a3.png
1.png

4.序列化|反序列化單例物件時,需要重寫 readResolve方法返回單例物件
5.靜態程式碼塊建立單例物件.

5423393-c31988fd9f42bdae.png
1.png

6.列舉實現單例模式.(使用列舉類時,構造方法被自動呼叫,在列舉的構造方法中建立單例類的單例物件)
23.執行緒的狀態
-new 至今尚未啟動(建立後還沒start)
-runnable 正在java虛擬機器中執行(可能獲得了CPU時間片,也可能沒獲得CPU時間片)
-blocked 受阻塞並等待某個鎖

-waiting      無限期的等待另一個執行緒來執行某一特定操作
-timewaitting    在指定時間內等待另一執行緒執行某一特定操作
-terminated    已退出的執行緒
5423393-371d9910cb92489e.png
1.png

1.單例模式的寫發

所有的單例模式都是建構函式私有化.成員以private static 修飾,提供公開static 方法訪問.不讓別人例項化他,

1.惡漢模式.就是載入類時候就載入,缺點是不能有其他例項變數,因為getInstance無法同步.
如果從始至終從未使用過這個例項,則會造成記憶體的浪費
  public class A{ 
    private static A obj =new A(); //直接例項化
     也可以使用靜態程式碼塊
    private static A obj;
    static {
      obj=new A();
    }
    private A(){}
    public static A getInstance(){
      return obj;
    }
  }

2.懶漢模式.呼叫時候載入,單執行緒的時候沒事.多執行緒會產生多個obj物件.
 public class A{
    private static A obj;
    private A(){}
    public static A getInstance(){
      if(obj ==null){
        //初始化東西
        obj =new A();
      }
        return obj;
    }
  }
3.懶漢模式加 synchronized 關鍵字. 方法加鎖.導致方法需要等待某執行緒執行完才釋放鎖.方法執行效率低.
public class A{
  private static A obj;
  private A(){}
  sychnorized public static A getInstance(){ 
      if(obj ==null){
      obj =new A();
      }
      return obj;
  }
}
4.另一種懶漢模式加鎖.其實和3是一樣的
public class A{
  private static A obj;
  private A(){}
  
  public static A getInstance(){
    synchronized(A.class){  //鎖住類物件,同時程式碼塊鎖要在 obj判斷外邊.不然沒意義.
         if(obj ==null){
            obj =new A();
         }
    }
    return obj;
   }
}
 5.懶漢模式加dcl(doublc check lock) 雙檢查鎖機制
    public class A {
      private volatile static A obj;   volatile關鍵字使所有執行緒強制去主儲存區拿obj變數.
      private A () {}
      public static A getInstance(){
        if(obj ==null){
              //這裡可以進行一些執行緒無關的初始化,保證不需要同步的程式碼非同步執行
              synchronized(A.class){   
                   if( obj ==null){ //這裡判空是為如果有執行緒阻塞,先前進來的已經建立完畢,就不需要在建立了.
                      obj=new A();
                    }
              }
       }
        return  obj;
      }
    }
6.使用靜態內部類, 不需要外部類的引用,效果同雙檢查鎖
採用了類裝載的機制來保證初始化例項時只有一個執行緒,
內部類是延時載入的,也就是說只會在第一次呼叫時載入。不呼叫就不載入
  public class A{
    private A(){}
    private static class B{
        private static A obj =new Object();
    }
    public static A getInstance{
        return B.obj;
    }
  }
7.列舉方式,在使用列舉時,構造方法被自動呼叫.不僅能避免多執行緒同步問題,而且還能防止反序列化重新建立新的物件,
每一個列舉型別和定義的列舉變數在JVM中都是唯一的
  public class B{
    public enum C{
       factory;  //列舉型別
       private A obj; //需要初始化的引數
        private C{  //列舉的建構函式會在呼叫列舉型別時候執行.
            obj =new A();
        }
        public  A getA(){
            return obl;
        }
    }
    public static A getInstance(){
      return B.factory.getA();
     }
  }
  8.單例模式在序列化時.重新讀取會生成新的物件.解決方法如下
public class A {
  private staitc A obj =new A();
  protected A(){}

  /反序列時直接返回當前INSTANCE
   private Object readResolve() {     //重寫這個方法.返回之前建立的
            return INSTANCE;     
      }    
}




相關文章