引言
在程序中,经常会遇到多个线程同时使用一个对象的情况。然而,多个线程同时操作同一对象可能导致意想不到的错误,因此会产生并发的问题。
为了解决这类问题,通常有两种解决办法。
- 时间换空间
在多个线程争抢同一对象时,按照某种排列顺序对这些线程进行排序。只有在当前线程使用完毕后,下一个线程才能使用。这就是锁的设计思想,一旦线程占有了对象,其他线程就无法再占用该对象。
- 空间换时间
争抢同一对象的时候,有另外一种解决办法。那就是将该对象复制多份,每个线程都独占一份。各个线程都独立开来,互不影响,那么并发自然而然就解决了。
概述
ThreadLocal
是从JDK1.2开始就存在的一个类,该类的描述为:为线程提供局部变量,该变量的不同之处在于每个变量的线程都有自己的、独立初始化的变量副本。
从这类的描述中,我们就能看出来,这个类天生符合上面提到的第二种解决方法:空间换时间。
基本用法
在Java中,需要反序列Date
类型的日期时,我们就需要用到SimpleDateFormat
这个工具类。但是这个工具类是线程不安全的,此时就需要用到ThreadLoca
来进行线程安全的保证了。
简单使用:
public class DateUtils {
private static final ThreadLocal<SimpleDateFormat> SDF =
ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy年MM月dd日"));
public static Date main(String date) {
return SDF.get().parse(date);
}
}
API介绍
ThreadLocal
类只向外提供了三个使用方法。
- set方法
可以传入一个泛型对象,将该对象存放于ThreadLocal中。
- get方法
获取ThreadLocal存放的内容。
- remove方法
清空ThreadLoca存放的内容。
示例:如何在代码中使用ThreadLocal
下面是一个简单的示例,操作在主线程中声明的一个thradLocal
变量。然后额外创建了两个线程,分别存放不同的值。
public class ThreadLocalDemo {
public static void main(String[] args) throws InterruptedException {
ThreadLocal<String> threadLocal = new ThreadLocal<>();
new Thread(() -> {
threadLocal.set("ThreadLocalHello");
System.out.println("Thread:" + Thread.currentThread().getName() + " ThreadLocalValue:" + threadLocal.get());
}).start();
Thread.sleep(5000);
new Thread(() -> {
threadLocal.set("ThreadLocalWorld");
System.out.println("Thread:" + Thread.currentThread().getName() + " ThreadLocalValue:" + threadLocal.get());
}).start();
}
}
控制台输出: