Java多線程 - ThreadLocal類的使用

  • ThreadLocal是線程的局部變量, 是每一個線程所單獨持有的,其他線程不能對其進行訪問

    • ThreadLocal支持泛型,也就是支持value是可以設置類型的,像是ThreadLocal<Date>就是設置value爲Date類型

    • 每個線程會有自己的一份ThreadLocalMap變量,去儲存這個線程自己想存放的ThreadLocal變量們,他內部儲存的是一個鍵值對Map,其中key是某個ThreadLocal,value就是這個線程自己set的值,所以對於一個線程來說,一個ThreadLocal只能存一個值,而一個線程可以存放好多個ThreadLocal

    • 因此當調用ThreadLocaltltl.get()方法時,其實就是先去取得此線程的ThreadLocalMap,然後再去查找這個Map中的key爲tl的那個Entry的value值

  • ThreadLocal常用的方法

    • set(x) : 設置此線程的想要放的值是多少

    • get() : 取得此線程當初存放的值,如果沒有存放過則返回null

    • remove() : 刪除此線程的鍵值對,也就是如果先執行remove再執行get,會返回null

  • ThreadLocal通常用在SimpleDateFormat,或是SpringMVC上

    • 因爲SimpleDateFormat不是線程安全的,因此雖然可以每次要使用的時候重新new一個,但是這樣做會很浪費資源,所以如果使用ThreadLocal在每個線程裡都存放一個此線程專用的SimpleDateFormat,就可以避免一直new的資源浪費,又確保線程安全

    • 因爲SpringMVC會對每個請求分配一個線程,可以在攔截器將此線程的用戶信息(ip、名字...)使用ThreadLocal儲存,這樣在後續要用到用戶信息的地方時,就可以去ThreadLocal中取得,而且因爲ThreadLocal可以隔離線程,因此每條請求對應的線程的用戶信息不會互相干擾

  • 具體實例

    • 每個線程都可以在ThreadLocal中放自己的值,且不會干擾到其他線程的值

      class Tools {
          public static ThreadLocal threadLocal = new ThreadLocal();
      }
      ​
      class MyThread extends Thread {
          @Override
          public void run() {
              if (Tools.threadLocal.get() == null) {
                  Tools.threadLocal.set(Thread.currentThread().getName() + ", " + Math.random());
              }
              System.out.println(Tools.threadLocal.get());
          }
      }
      ​
      public class Main {
          public static void main(String[] args) {
              for (int i = 0; i < 5; i++) {
                  MyThread thread = new MyThread();
                  thread.setName("thread " + i);
                  thread.start();
              }
          }
      } Tools {
          public static ThreadLocal threadLocal = new ThreadLocal();
      }
      ​
      class MyThread extends Thread {
          @Override
          public void run() {
              if (Tools.threadLocal.get() == null) {
                  Tools.threadLocal.set(Thread.currentThread().getName() + ", " + Math.random());
              }
              System.out.println(Tools.threadLocal.get());
          }
      }
      ​
      public class Main {
          public static void main(String[] args) {
              for (int i = 0; i < 5; i++) {
                  MyThread thread = new MyThread();
                  thread.setName("thread " + i);
                  thread.start();
              }
          }
      }
      thread 1, 0.86
      thread 0, 0.42
      thread 2, 0.35
      thread 3, 0.41
      thread 4, 0.45
      thread 0, 0.42
      thread 2, 0.35
      thread 3, 0.41
      thread 4, 0.45
    • 使用ThreadLocal在SimpleDateFormat上,並且給ThreadLocal加上泛型,指定value的類型是SimpleDateFormat

      • 因爲使用了ThreadLocal確保每個線程有自己一份SimpleDateFormat,所以線程安全,不會報錯

      class Tools {
          public static ThreadLocal<SimpleDateFormat> threadLocal = new ThreadLocal<SimpleDateFormat>();
      }
      ​
      class MyThread extends Thread {
          @Override
          public void run() {
              SimpleDateFormat sdf = Tools.threadLocal.get();
              if (sdf == null) {
                  sdf = new SimpleDateFormat("yyyy-MM-dd");
                  Tools.threadLocal.set(sdf);
              }
              try {
                  System.out.println(sdf.parse("2018-07-15"));
              } catch (ParseException e) {
                  System.out.println("報錯了");
              }
          }
      }
      ​
      public class Main {
          public static void main(String[] args) {
              for (int i = 0; i < 5; i++) {
                  MyThread thread = new MyThread();
                  thread.setName("thread " + i);
                  thread.start();
              }
          }
      } Tools {
          public static ThreadLocal<SimpleDateFormat> threadLocal = new ThreadLocal<SimpleDateFormat>();
      }
      ​
      class MyThread extends Thread {
          @Override
          public void run() {
              SimpleDateFormat sdf = Tools.threadLocal.get();
              if (sdf == null) {
                  sdf = new SimpleDateFormat("yyyy-MM-dd");
                  Tools.threadLocal.set(sdf);
              }
              try {
                  System.out.println(sdf.parse("2018-07-15"));
              } catch (ParseException e) {
                  System.out.println("報錯了");
              }
          }
      }
      ​
      public class Main {
          public static void main(String[] args) {
              for (int i = 0; i < 5; i++) {
                  MyThread thread = new MyThread();
                  thread.setName("thread " + i);
                  thread.start();
              }
          }
      }
      Sun Jul 15 00:00:00 CST 2018
      Sun Jul 15 00:00:00 CST 2018
      Sun Jul 15 00:00:00 CST 2018
      Sun Jul 15 00:00:00 CST 2018
      Sun Jul 15 00:00:00 CST 2018
      Sun Jul 15 00:00:00 CST 2018
      Sun Jul 15 00:00:00 CST 2018
      Sun Jul 15 00:00:00 CST 2018
      Sun Jul 15 00:00:00 CST 2018
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章