ThreadLocal

来源:互联网 发布:ubuntu命令行更新软件 编辑:程序博客网 时间:2024/06/18 03:25

类ThreadLocal主要解决的就是每个线程绑定自己的值,可以将ThreadLocal类比喻成全局存放数据的盒子,盒子中可以存储每个线程的私有数据。

ava中的ThreadLocal类允许我们创建只能被同一个线程读写的变量。因此,如果一段代码含有一个ThreadLocal变量的引用,即使两个线程同时执行这段代码,它们也无法访问到对方的ThreadLocal变量。

如何创建ThreadLocal变量
以下代码展示了如何创建一个ThreadLocal变量:

private ThreadLocal myThreadLocal = new ThreadLocal();
我们可以看到,通过这段代码实例化了一个ThreadLocal对象。我们只需要实例化对象一次,并且也不需要知道它是被哪个线程实例化。虽然所有的线程都能访问到这个ThreadLocal实例,但是每个线程却只能访问到自己通过调用ThreadLocal的set()方法设置的值。即使是两个不同的线程在同一个ThreadLocal对象上设置了不同的值,他们仍然无法访问到对方的值。

如何访问ThreadLocal变量
一旦创建了一个ThreadLocal变量,你可以通过如下代码设置某个需要保存的值:

myThreadLocal.set(“A thread local value”);
可以通过下面方法读取保存在ThreadLocal变量中的值:

String threadLocalValue = (String) myThreadLocal.get();
get()方法返回一个Object对象,set()对象需要传入一个Object类型的参数。

为ThreadLocal指定泛型类型
我们可以创建一个指定泛型类型的ThreadLocal对象,这样我们就不需要每次对使用get()方法返回的值作强制类型转换了。下面展示了指定泛型类型的ThreadLocal例子:

1
private ThreadLocal myThreadLocal = new ThreadLocal();
现在我们只能往ThreadLocal对象中存入String类型的值了。

并且我们从ThreadLocal中获取值的时候也不需要强制类型转换了。

一个完整的ThreadLocal例子
下面是一个完整的可执行的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对象,因此这两个线程都无法看到对方保存的值。也就是说,它们存取的是两个不同的值。

使用场景
曾经很疑惑ThreadLocal是干什么用?什么场景下要用?
查了几篇文章,都说它的优势是线程安全,想必他的作用就是为了线程安全吧。
仔细理解后发现,原来我们常用的局部变量和静态变量,在某种情况下无法满足要求,比如,我要求缓存一个变量,这个时候你肯定会说搞一个静态map存一下就OK了,但是有几个问题:
第一:其他线程擅自修改我的这个静态map怎么办?
第二:静态map之间并发访问怎么办?
当然,也有人说而已使用局部变量,然后通过传递引用来实现在不同的场合使用,但是这样就要依赖具体方法的入参和出参,至少你要增加一个入参来传入这个引用吧?

这种情况下,ThreadLocal就可以发挥他的威力了,它的本质就是一个内部的静态map,key是当前线程的一个句柄,value是需要保存的值,当然value可以是任何类型的,至少是一个map或者容器把,不然一个线程就只能存一个value了,太不实用。
基于上面这种设计,每个线程其实根本无法获取到其他线程的key,由于是内部静态map,不提供遍历和查询的接口,也确保了其他线程只能根据key获取,所以,每个线程只能取到自己线程的value。
这样,即做到了线程安全,又在线程范围内提供了数据共享的能力。

原创粉丝点击