JAVA並發編程之線程局部變量


      共享數據是並發程序最核心的問題之一,對於繼承Thread類或者實現Runnable接口的對象來說尤其重要。

      如果創建的對象實現了Runnable接口的類的實例,用它作為傳入參數,並創建多個線程對象並啟動這些線程,那么所有的線程將共享相同的屬性。如果在一個線程中改變一個屬性,所有線程都會被這個改變影響。

     在某種情況下,這個對象的屬性不需要被所有線程共享。JAVA提供了一個比較好的機制,即線程局部變量(Thread-Local Variable).

     我們寫一個簡單的DEMO,一是具有剛才提到的問題,另一個使用線程局部變量機制解決這個問題。

     1.創建一個類為UnsafeTask的類,它實現了Runnable接口。並且聲明一個java.util.Date屬性。

       public class UnsafeTask implements Runnable{
       private Date startDate;  }

    2.實現run()方法。這個方法初始化startDate屬性,並且將值打印到控制台。讓線程休眠一個隨機時間,然后再次將值打印到控制台。

       public void run(){
          startDate=new Date();
          System.out.printf("Starting Thread:%s:%s \n",Thread.currentThread().getId(),startDate);
          try{
              TimeUnit.SECONDS.sleep((int)Math.rint(Math.random()*10));
          }catch(InterruptedException e){
              e.printStackTrace();
          }
          System.out.printf("Thread Finished:%s :%s\n",Thread.currentThread().getId(),startDate);
       }

     3.創建一個Main主類,並包含了一個main()方法。這個方法將創建一個UnsafeTask類對象,用它作為傳入參數創建10個線程對象並啟動10個線程,每個線程啟動時間間隔為2秒。

    public class Main {
     public static void main(String[] args){
         UnsafeTask task=new UnsafeTask();
         for(int i=0;i<10;i++){
             Thread thread=new Thread(task);
             thread.start();
             try{
                TimeUnit.SECONDS.sleep(2);
             }catch(InterruptedException e){
                 e.printStackTrace();
                
             }
         }
     }
}

   4.運行結果如圖

     

      每個線程有一個不同的開始時間。他們結束時,三個線程就有相同的startDate屬性值。

    

      5.接下來我們使用線程局部變量機制來解決上述問題。

      6.創建一個SafeTask類,用以實現Runnable接口。

        public class SafeTask implements Runnable{}

     7.聲明一個ThreadLocal<Date>對象。這個對象是在initialValue()方法中隱式實現,返回當前日期。

        private static ThreadLocal<Date> startDate=new ThreadLocal<Date>(){
           protected Date initalValue(){
               return new Date();
           }
      };

      8.實現run()方法。跟上面方法實現一樣功能,但是startDate屬性方式改變了。

       public void run(){
        System.out.printf("Starting Thread: %s : %s\n",Thread.currentThread().getId(),startDate.get());
          try {
              TimeUnit.SECONDS.sleep((int)Math.rint(Math.random()*10));
          } catch (InterruptedException e) {
              e.printStackTrace();
          }
          
          System.out.printf("Thread Finished: %s : %s\n",Thread.currentThread().getId(),startDate.get());
      }

      9.Main主類同上,只是創建並作為參數傳入的Runnable類對象不同而已。

      public class Main {
     public static void main(String[] args){
         SafeTask task=new SafeTask();
         for(int i=0;i<3;i++){
             Thread thread=new Thread(task);
        
             try{
                TimeUnit.SECONDS.sleep(2);
             }catch(InterruptedException e){
                 e.printStackTrace();
                
             }
             thread.start();
         }
     }
}

     10.運行結果。

   

    

  

      


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM