详解ThreadLocal类

来源:互联网 发布:淘宝一天才十几个访客 编辑:程序博客网 时间:2024/05/19 15:21

在学习多线程编程的过程中,都会碰到一个重要的类——ThreadLocal。接下来,将从如下几方面来讲述:

1.什么是ThreadLocal?

其为线程局部变量,为每一个使用该变量的线程提供一个变量值副本,使得每一个线程可以独自占有,不会与其他线程产生冲突。接下来看下该接口的设计:

  • protected ThreadLocal initialValue():子类可以重写该方法,在ThreadLocal中期直接返回null。该方法返回当前线程在该线程局部变量的初始值,这个方法是一个延迟调用方法,在一个线程第1次调用get()或者set(Object)时才执行,并且仅执行1次。
  • public T get(),返回当前线程的线程局部变量副本。
  • public void set(T value),设置当前线程的线程局部变量副本的值。从jdk5.0的src来看,并非在ThreadLocal中有一个Map,而是在每个Thread中存在这样一个Map,具体是ThreadLocal.ThreadLocalMap。当用set时候,往当前线程里面的Map里 put 的key是当前的ThreadLocal对象。而不是把当前Thread作为Key值put到ThreadLocal中的Map里。如下代码:

         public void set(T value) {
             Thread t = Thread.currentThread();
             ThreadLocalMap map = getMap(t);
             if (map != null)
                map.set(this, value);
             else
                createMap(t, value);
         }

  • public void remove(),移除当前线程的线程局部变量副本的值以释放存储空间。


2.怎么使用该类?

简单举个例子:

public class MyThread implements Runnable{
   
    private int val;
   
    MyThread(int val){
        this.val = val;
    }
    public void run() {
        // TODO Auto-generated method stub
       
        ThreadLocalExample.setThreadId(val);
       
        for(int i=0;i<5;i++){
            System.out.println("thread:"+Thread.currentThread().getId()+" val:"+ThreadLocalExample.getValue());
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
       
    }
   
}

public class ThreadLocalExample {
    private static ThreadLocal local = new ThreadLocal();
   
    public static void setThreadId(int val){
        local.set(val);
    }
   
    public static int getValue(){
        return ((Integer)local.get()).intValue();
    }
   
    public static void main(String[] args){
        Thread t1 = new Thread(new MyThread(1));
        Thread t2 = new Thread(new MyThread(2));
        t1.start();
        t2.start();
    }
}

运行结果:

thread:8 val:1
thread:9 val:2
thread:8 val:1
thread:9 val:2
thread:8 val:1
thread:9 val:2
thread:8 val:1
thread:9 val:2
thread:8 val:1
thread:9 val:2

从中可以看出,代码中没有明显的进行同步代码的控制,但是使用了ThreadLocal可以很好的让线程独享自己的变量,相互没有影响。


3.ThreadLocal和其他同步机制之间的差别或优势?

ThreadLocal和其它所有的同步机制都是为了解决多线程中的对同一变量的访问冲突,在普通的同步机制中,是通过对象加锁来实现多个线程对同一变量的安全访问的。这时该变量是多个线程共享的,使用这种同步机制需要很细致地分析在什么时候对变量进行读写,什么时候需要锁定某个对象,什么时候释放该对象的锁等等很多。所有这些都是因为多个线程共享了资源造成的。ThreadLocal就从另一个角度来解决多线程的并发访问,ThreadLocal会为每一个线程维护一个和该线程绑定的变量的副本,从而隔离了多个线程的数据,每一个线程都拥有自己的变量副本,从而也就没有必要对该变量进行同步了。ThreadLocal提供了线程安全的共享对象,在编写多线程代码时,可以把不安全的整个变量封装进ThreadLocal,或者把该对象的特定于线程的状态封装进ThreadLocal
  当然ThreadLocal并不能替代同步机制,两者面向的问题领域不同。同步机制是为了同步多个线程对相同资源的并发访问,是为了多个线程之间进行通信的有效方式;而ThreadLocal隔离多个线程的数据共享,从根本上就不在多个线程之间共享资源(变量),这样当然不需要对多个线程进行同步了。所以,如果你需要进行多个线程之间进行通信,则使用同步机制;如果需要隔离多个线程之间的共享冲突,可以使用ThreadLocal,这将极大地简化我们的程序,使程序更加易读、简洁。