Java中的多線程(二)

 5. 線程的同步安全

    多線程的安全問題來自於當不一樣線程切換時,對同一數據的操做引發的混亂。例如兩個線程併發同時對同一個文件修改時就有可能形成異常。對於線程的同步,Java提供了以下幾種方式解決:多線程

    a. 同步代碼塊併發

    Java的多線程支持引入同步監視器來解決這個問題。ide

 

      
      
               
      
      
  1. synchronized(obj){  //括號中的obj就是同步監視器
  2.  
  3.      ...  
  4.      //此處的代碼就是同步代碼塊  
  5. //上述代碼的含義就是,線程開始執行同步代碼塊以前,必須先得到對同步監視器的鎖定。一般推薦使用可能被併發訪問的共享資源充當同步監視器。

    這樣一來,任何想要修改制定資源的資源執行時,首先說該資源加鎖,在加鎖期間其它進程沒法修改該資源,而在其修改完成以後便釋放對該資源的鎖定。從而使得同一時刻只有一條線程處於臨界區內,保證了安全。學習

    須要注意的是,同步監視器通常能夠由任何對象充當,只要其惟一恆定就能夠,一般推薦使用可能被併發訪問的共享資源充當同步監視器。this

    b. 同步方法spa

    在Java中的多線程中,使用synchronized關鍵字修飾的方法成爲同步方法。對於同步方法,就無需指定監視器,該對象自己就是監視器。在同步方法執行的時候,就會首先鎖定同步監視器this,synchronized保證了只有一條線程對資源的訪問。因此,應該把同步方法定義在須要被獨佔訪問的對象類內部。線程

  c. 同步鎖對象

    同步鎖是線程同步的另外一種機制。使用被聲明爲final的同步鎖做爲同步監視器,在方法體執行前首先顯式加鎖,執行完後在顯式的解鎖,因爲使用Lock對象時每一個Lock對象都對應一個被訪問的對象,其實也就等同於同步方法的實現機制,保證了線程的同步。接口

 

 
 

      
      
               
      
      
  1. class X{90 
  2. //定義鎖對象  
  3. private final ReentrantLook lock=new ReentrantLook();  
  4. //...  
  5. //定義須要保證線程安全的方法  
  6. public void m(){  
  7. //加鎖  
  8. lock.lock();  
  9. try{  
  10. //方法體  
  11. //.....  
  12. }finally{  
  13. //解鎖  
  14. lock.unlock();  
  15.       }  
  16.   }   

    

    以上的各類線程同步機制,其實就是以一個始終恆定不變的對象做爲同步監視器。在同步塊代碼中,雖然方法定義在線程類的內部,可是做爲同步監視器的被訪問對象是在初始化以後從外部傳遞到其內部的,具備不變性。而在同步方法機制中,同步監視器就是this對象,當對象初始化時,已經恆定了對象,因此其同步監視器也是不變的。Lock機制和同步方法的機制相似,只不過其監視器是lock,由於當初始化獨佔訪問對象時也會初始化lock,因此也是恆定的。

  6. 線程通訊

  a. 控制線程協調運行的機制(1)

    Java中有內置的三種方法對線程進行協調控制,他們屬於Object類,但調用的時候要使用同步監視器來調用。

    wait()方法使當前線程等待,釋放對該同步器的鎖定。

    notify()方法喚醒該同步器上等待的單個線程,對於喚醒的選擇是任意的。

    notify()喚醒所有等待的線程。

  b. 控制線程協調運行的機制(2)

    在使用了Lock對象保證同步的的程序中,同步監視器並不是this對象自己,就要使用Condition對象的的方法保證同步。   

 

 
 

      
      
               
      
      
  1. //顯式的得到Lock對象  
  2. private final Lock lock=new() ReentrantLock();  
  3. //得到指定Lock對象的條件變量  
  4. private final Condition cond=lock.newCondition();  
  5. //.....  
  6. cond.await();  
  7. //.....  
  8. cond.signal();  
  9. //.....  
  10. cond.signalAll();  

    這三個方法的功能同上面的三個方法功能。

  c. 使用管道流進行通訊

    同I/O流中的機制(在I/O學習以後補上該部分)

  7. 線程池

    線程池在系統啓動時即建立大量線程,程序將一個Runnable或者Callable對象傳給一個線程池,線程池就會啓動一條線程執行該對象的run方法,當run方法執行結束後,該線程不會死亡,而是從新返回線程池成爲空閒狀態。

 

 
 

      
      
               
      
      
  1. //實現Runnable接口來定義一個簡單的  
  2. class TestThread implements Runnable  
  3. {  
  4.     public void run()  
  5.     {  
  6.         for (int i = 0; i < 100 ; i++ )  
  7.         {  
  8.             System.out.println(Thread.currentThread().getName()  
  9.                 + "的i值爲:" + i);  
  10.         }  
  11.     }  
  12. }  
  13.  
  14. public class ThreadPoolTest  
  15. {  
  16.     public static void main(String[] args)   
  17.     {  
  18.         //建立一個具備固定線程數(6)的線程池  
  19.         ExecutorService pool = Executors.newFixedThreadPool(6);  
  20.         //向線程池中提交2個線程  
  21.         pool.submit(new TestThread());  
  22.         pool.submit(new TestThread());  
  23.         //關閉線程池  
  24.         pool.shutdown();  
  25.     }  
  26. }  
相關文章
相關標籤/搜索