ThrealLocal使用場景

  • 每個線程需要獨享的對象,且這個對象是線程不安全的,所以需要ThreadLocal給每個線程複製一份 eg:Random、SimpleDateFormat 都是線程不安全的;

以下代碼是通過線程池來打印各個線程的時間

`

 public static ExecutorService executorService = Executors.newFixedThreadPool(10);
 public static SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");

 public static void main(String[] args) {
     for (int i = 0; i < 10; i++) {
         int finalI = i;
         executorService.submit(new Runnable() {
             @Override
             public void run() {
                 Date date = TenThreadTest.date(finalI);
                 System.out.println(simpleDateFormat.format(date));
             }
         });
     }
     executorService.shutdown();
 }

 public static   Date date (int seconds) {
     return new Date(1000 * seconds);
 }

`

以上代碼執行結果

`

  1970-01-01 08:00:02
  1970-01-01 08:00:06
  1970-01-01 08:00:05
  1970-01-01 08:00:02
  1970-01-01 08:00:02
  1970-01-01 08:00:08
  1970-01-01 08:00:02
  1970-01-01 08:00:02
  1970-01-01 08:00:09
  1970-01-01 08:00:07

`

大家有沒有發現一個問題就是執行結果中存在重複的時間,根本原因就是 SimpleDateFormat 是線程不安全的,所有的線程共SimpleDateFormat,我們可以通過synchronized加鎖,但是synchronized是阻塞的,如果線程的任務量特別大,效率會特別低;

以下是通過ThreadLocal加持過得實現方式:
十個線程都會有自己的 SimpleDateFormat 都是線程獨享的

`

   public static ExecutorService executorService = Executors.newFixedThreadPool(10);

   public static void main(String[] args) {
       for (int i = 0; i < 1000; i++) {
           int finalI = i;
           executorService.submit(new Runnable() {
               @Override
               public void run() {
                   SimpleDateFormat simpleDateFormat = ThreadLocalFormat.simpleDateFormatThreadLocal.get();
                   Date date = TenThreadTest.date(finalI);
                   System.out.println(simpleDateFormat.format(date));
               }
           });
       }
       executorService.shutdown();
   }

   public static   Date date (int seconds) {
       return new Date(1000 * seconds);
   }

   static class ThreadLocalFormat {
       public static  ThreadLocal<SimpleDateFormat> simpleDateFormatThreadLocal = ThreadLocal.withInitial(() ->
               new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"));
   }

`

  • 每個線程內需要全局變量,不需要傳參,可以讓不同的方法直接使用

以下代碼讓當前用戶在當前線程暢通無阻,不需要層層傳遞參數

`

package thread;

public class UsePart2 {

 public static void main(String[] args) {
     User user = new User();
     user.setName("王哈哈");
     UserContentHolder.threadLocal.set(user);

     new Service1().process();
     new Service2().process();
     new Service3().process();
 }

}

 class Service1 {
     public void process() {
         System.out.println("service1" + UserContentHolder.threadLocal.get().getName());
     }
 }
 
 
 class Service2 {
     public void process() {
         System.out.println("service2" + UserContentHolder.threadLocal.get().getName());
     }
 }


 class Service3 {
     public void process() {
         System.out.println("service3" + UserContentHolder.threadLocal.get().getName());
     }
 }
 
 class UserContentHolder{
     public static ThreadLocal<User> threadLocal = new ThreadLocal<User>();
}

 class User {
     public String getName() {
         return name;
     }

     public void setName(String name) {
         this.name = name;
     }
 
     private String name;
 }

`

運行結果:

`

service1王哈哈
service2王哈哈
service3王哈哈

`

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章