ThreadLocal
ThreadLocal
多线程访问同一个共享变量的时候容易出现并发问题,特别是多个线程对一个变量进行写入的时候,为了保证线程安全,一般在访问共享变量的时候需要进行额外的同步措施才能保证线程安全性。ThreadLocal是除了加锁这种同步方式之外的另一种保证多线程访问时线程安全的方法,当我们在创建一个变量后,如果每个线程对其进行访问的时候访问的都是线程自己的变量这样就不会存在线程不安全问题。
ThreadLocal是JDK包提供的,它提供线程本地变量,如果创建一个ThreadLocal变量,那么访问这个变量的每个线程都会有这个变量的一个副本,在实际多线程操作的时候,操作的是自己本地内存中的副本变量,从而规避了线程安全问题
简单使用
threadlocal使用方法很简单
static final ThreadLocal<T> sThreadLocal = new ThreadLocal<T>();
sThreadLocal.set()
sThreadLocal.get()
threadlocal而是一个线程内部的存储类,可以在指定线程内存储数据,数据存储以后,只有指定线程可以得到存储数据,官方解释如下。
/**
* This class provides thread-local variables. These variables differ from
* their normal counterparts in that each thread that accesses one (via its
* {@code get} or {@code set} method) has its own, independently initialized
* copy of the variable. {@code ThreadLocal} instances are typically private
* static fields in classes that wish to associate state with a thread (e.g.,
* a user ID or Transaction ID).
*/
大致意思就是ThreadLocal提供了线程内存储变量的能力,这些变量不同之处在于每一个线程读取的变量是对应的互相独立的。通过get和set方法就可以得到当前线程对应的值。
下面是一个使用实例:
/**
在多线程环境中,把字符串转换为日期对象,多个线程使用同一个SimpleDateFormat对象可能会产生线程安全问题,需要为每个线程指定自己的SimpleDateFormat对象,使用ThreadLocal
*/
public class ThreadLocalTest {
private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日HH:mm:ss");
static ThreadLocal<SimpleDateFormat> threadLocal = new ThreadLocal<>();
static class ParseDate implements Runnable{
private int i = 0;
public ParseDate(int i){
this.i = i;
}
@Override
public void run() {
try {
String text = "2068年11月22日08:28:" + i %60;
//先判断当前线程是否有SimpleDateFormat对象,如果当前线程没有SimpleDateFormat对象就创建一个,如果有就直接使用
if (threadLocal.get() == null) {
System.out.println("创建SimpleDateFormat对象");
threadLocal.set(new SimpleDateFormat("yyyy年MM月dd日HH:mm"));
}
Date date = threadLocal.get().parse(text);
System.out.println(i + "--" + date);
} catch (ParseException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
new Thread(new ParseDate(i)).start();
}
}
}