Java ThreadLocal的使用

Posted 玉龙小主

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java ThreadLocal的使用相关的知识,希望对你有一定的参考价值。

1.ThreadLocal用来解决多线程程序的并发问题
2.ThreadLocal并不是一个Thread,而是Thread的局部变量,当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每个线程都
可以独立地改变自己的副本,而不会影响其它线程所对应的副本.
3.从线程的角度看,目标变量就象是线程的本地变量,这也是类名中“Local”所要表达的意思。
4.线程局部变量并不是Java的新发明,Java没有提供在语言级支持(语法上),而是变相地通过ThreadLocal的类提供支持.
5.ThreadLocal类中的方法:(JDK5版本之后支持泛型)
void set(T value)
将此线程局部变量的当前线程副本中的值设置为指定值
void remove()
移除此线程局部变量当前线程的值
protected T initialValue()
返回此线程局部变量的当前线程的“初始值”
T get()
返回此线程局部变量的当前线程副本中的值
6.ThreadLocal的原理:
ThreadLocal是如何做到为每一个线程维护变量的副本的呢?其实实现的思路很简单:在ThreadLocal类中有一个Map,用于存储每一个线程的变量副本,Map中元素
的键为线程对象,而值对应线程的变量副本
7.自己模拟ThreadLocal:

public class SimpleThreadLocal{
private Map valueMap=Collections.synchronizedMap(new HashMap());
public void set(Object newValue){
valueMap.put(Thread.currentThread(),newValue);//键为线程对象,值为本线程的变量副本
}
public Object get(){
Thread currentThread=Thread.currentThread();
Object o=valueMap.get(currentThread);//返回本线程对应的变量
if(o==null&&!valueMap.containsKey(currentThread)){
//如果在Map中不存在,放到Map中保存起来
o=initialValue();
valueMap.put(currentThread,o);
}
return o;
}
public void remove(){
valueMap.remove(Thread.currentThread());
}
public void initialValue(){
return null;
}
}

 


8.使用ThreadLocal的具体例子:

public class SequenceNumber{
//通过匿名内部类覆盖ThreadLocal的initialValue()方法,指定初始值
private static ThreadLocal<Integer> seNum=new ThreadLocal<Integer>(){
protected Integer initialValue(){
return 0;
}
}
public Integer getNextNum(){
seNum.set(seNum.get()+1);
return seNum.get();
}
public static void main(String[] args){
SequenceNumber sn=new SequenceNumber();
//3个线程共享sn,各自产生序列号
TestClient t1 = new TestClient(sn);
TestClient t2 = new TestClient(sn);
TestClient t3 = new TestClient(sn);
t1.start();
t2.start();
t3.start();
}
private static class TestClient extends Thread{
private SequenceNumber sn;
public TestClient(SequenceNumber sn){
this.sn=sn;
}
public void run(){
//每个线程打印3个序列号
for(int i=0;i<3;i++){
System.out.println("thread["+Thread.currentThread().getName()+",sn["+sn.getNextNum()+"]");
}
}
}
}

9.下面是一个完整的可执行的ThreadLocal例子:

       public class ThreadLocalExample {
        public static class MyRunnable implements Runnable {
            private ThreadLocal threadLocal = new ThreadLocal();
            @Override
            public void run() {
                threadLocal.set((int) (Math.random() * 100D));
                try {
                Thread.sleep(2000);
                } catch (InterruptedException e) {
                }
                System.out.println(threadLocal.get());
            }
        }
        public static void main(String[] args) {
             MyRunnable sharedRunnableInstance = new MyRunnable();
             Thread thread1 = new Thread(sharedRunnableInstance);
             Thread thread2 = new Thread(sharedRunnableInstance);
             thread1.start();
             thread2.start();
        }
    }

上面的例子创建了一个MyRunnable实例,并将该实例作为参数传递给两个线程。两个线程分别执行run()方法,并且都在ThreadLocal实例上保存了不同的值。如果它们访问的不是ThreadLocal对象并且调用的set()方法被同步了,则第二个线程会覆盖掉第一个线程设置的值。但是,由于它们访问的是一个ThreadLocal对象,因此这两个线程都无法看到对方保存的值。也就是说,它们存取的是两个不同的值。























以上是关于Java ThreadLocal的使用的主要内容,如果未能解决你的问题,请参考以下文章

Java学习笔记——ThreadLocal类的使用

java中的ThreadLocal详解及示例代码

Java 单线程代码ThreadLocal串值问题

14Java并发性和多线程-Java ThreadLocal

Java 8 ThreadLocal 源码解析

Java并发编程之ThreadLocal内存泄漏探究