Spring事务_03_ThreadLocal与线程同步

Spring事务_ThreadLocal与线程同步_03

ThreadLocal基础知识

  1. 在JDK1.2版本中就提供java.lang.ThreadLocal,ThreadLocal为解决多线程程序的并发提供了一种新思路。
  2. ThreadLocal不是一个线程,是线程的一个本地化的一个对象。当工作于多线程中的对象使用ThreadLocal维护变量时,为每个使用该变量的线程分配一个独立的变量副本。让每个线程都可以独立的改变自己的副本,而不影响其他线程的副本。
  3. 线程局部变量并不是Java发明的,其他的语言在语法层面提供了线程的局部变量。
  • ThreadLocal的接口方法

      void set(Object value)
          设置当前线程的局部变量
      public Object get()
          该方法返回当前线程所对应的线程局部变量;
      public void remove()
          将当前线程的局部变量的值删除。jdk1.5添加的方法,当线程结束之后,局部变量会被回收。
      protected Object initialValue()
          返回该局部变量的初始值,这个方法是protected修饰的,是被用来子类覆盖的。
          当第一次调用get或者set方法才会被调用。
    

    JDK1.5之后,ThreadLocal开始支持泛型。

    ThreadLocal的实现思路很简单,在ThreadLocal类中维护一个Map,用户存储线程变量的副本,Map中的元素的键为线程的对象,而值对应线程的变量副本。

      /**
       * ThreadLocal 实现原理
       * Created by Administrator on 2017/5/30.
       */
      public class SimpleThreadLocal<T> {
          private Map valeMap = Collections.synchronizedMap(new HashMap());
      
          public void set(T newValue){
              valeMap.put(Thread.currentThread(),newValue);
          }
      
          public T get(){
              Thread currentThread = Thread.currentThread();
              T o = (T) valeMap.get(currentThread);
              if(o==null&&!valeMap.containsKey(currentThread)){
                  o = initvalValue();
                  valeMap.put(currentThread,o);
      
              }
              return o;
          }
      
          protected T initvalValue(){
              return null;
          }
      
      }
    
  • ThreadLocal使用

      /**
       * ThreadLocal实例
       * Created by Administrator on 2017/5/30.
       */
      public class SequenceNumber {
          private static ThreadLocal<Integer> seqNum = new ThreadLocal<Integer>(){
              @Override
              protected Integer initialValue() {
                  return 0;
              }
          };
      
          public int getNextNum(){
              seqNum.set(seqNum.get()+1);
              return seqNum.get();
          }
      
          public static void main(String[] args) {
              SequenceNumber sn = new SequenceNumber();
              TestClient testClient1= new TestClient(sn);
              TestClient testClient2= new TestClient(sn);
              TestClient testClient3= new TestClient(sn);
      
              testClient1.start();
              testClient2.start();
              testClient3.start();
      
          }
      
      
          private static class TestClient extends Thread{
              private SequenceNumber sn;
      
              public TestClient(SequenceNumber sn){
                  this.sn = sn;
              }
      
              @Override
              public void run() {
                  for (int i = 0; i < 3; i++) {
                      System.out.println("thread["+
                      Thread.currentThread().getName()+"]sn["+sn.getNextNum()+"]");
                  }
              }
          }
      
      }
    
  • 执行结果:

    thread[Thread-1]sn[1]
    thread[Thread-0]sn[1]
    thread[Thread-0]sn[2]
    thread[Thread-0]sn[3]
    thread[Thread-1]sn[2]
    thread[Thread-1]sn[3]
    thread[Thread-2]sn[1]
    thread[Thread-2]sn[2]
    thread[Thread-2]sn[3]

ThreadLocalshi使用空间换取时间的思想,访问并行化,对象独享化。synchroniz仅提供一份变量,让不同的线程排队去访问,而ThreadLocal为每一个线程都提供一份变量,因此可以同时访问而互不影响。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,958评论 19 139
  • 在一般性开发中,笔者经常看到很多同学在对待java并发开发模型中只会使用一些基础的方法。比如Volatile,sy...
    张勇_bf29阅读 709评论 0 1
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,766评论 18 399
  • 很多时候我们讲KVO,使用的时候需要注意移除监听,循环引用等问题,但是在自定义KVO的时候,却容易忽视几个问题。 ...
    码农苍耳阅读 267评论 0 0
  • 体验入: 【变】 一开始会有一些不适应,做完后发现自己可以的!很有成就感,身边的环境也不一样的… 【爱】 沿着八大...
    能量在此阅读 151评论 0 1