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
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值