一、ThreadLocal应用
作用: 解决线程安全性问题。 常用方法: set() 在当前线程范围内,设置一个值存储到ThreadLocal中,这个值仅对当前线程可见。相当于在当前线程范围内建立了副本。 get() 从当前线程范围内取出set方法设置的值. remove() 移除当前线程中存储的值 withInitial java8中的初始化方法 案例 ThreadLocalDemo.java
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadLocalDemo {
//非线程安全的
private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
private static ThreadLocal<DateFormat> dateFormatThreadLocal = new ThreadLocal<>();
private static DateFormat getDateFormat() {
DateFormat dateFormat = dateFormatThreadLocal.get(); //从当前线程的范围内获得一个DateFormat
if (dateFormat == null) {
dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//Thread.currentThread();
dateFormatThreadLocal.set(dateFormat); //要在当前线程的范围内设置一个simpleDateFormat对象.
}
return dateFormat;
}
public static Date parse(String strDate) throws ParseException {
return getDateFormat().parse(strDate);
}
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(10);
for (int i = 0; i < 20; i++) {
executorService.execute(() -> {
try {
//sdf.parse("2021-05-30 20:12:20");
System.out.println(parse("2021-05-30 20:12:20"));
} catch (ParseException e) {
e.printStackTrace();
}
});
}
}
}
ThreadLocalExample.java
public class ThreadLocalExample {
//希望每一个线程获得的num都是0
// private static int num=0;
//全局用户信息的存储
static ThreadLocal<Integer> local= ThreadLocal.withInitial(() -> 0);
public static void main(String[] args) {
Thread[] thread=new Thread[5];
for(int i=0;i<5;i++){
thread[i]=new Thread(()->{
int num=local.get().intValue();
local.set(num+=5);
System.out.println(Thread.currentThread().getName()+" "+local.get());
});
}
//local=null;
for (int i = 0; i < 5; i++) {
thread[i].start();
}
}
}
二、ThreadLocal原理分析
ThreadLocal原理猜想 能够实现线程的隔离,当前保存的数据,只会存储在当前线程范围内。 存储结构是键值对,key是ThreadLocal对象,value是当前线程设置的值。 ThreadLocal源码分析
public void set(T value) {
Thread t = Thread.currentThread();
// 如果当前线程已经初始化了map。
// 如果没有初始化,则进行初始化。
ThreadLocalMap map = getMap(t);
if (map != null) //修改value
map.set(this, value);
else //初始化
createMap(t, value);
}
ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {
table = new Entry[INITIAL_CAPACITY]; //默认长度为16的数组
int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1); //计算数组下标
table[i] = new Entry(firstKey, firstValue); //把key/value存储到i的位置.
size = 1;
setThreshold(INITIAL_CAPACITY);
}
private void set(ThreadLocal<?> key, Object value) {
Entry[] tab = table;
int len = tab.length;
int i = key.threadLocalHashCode & (len-1); //计算数组下标()
//线性探索.()
for (Entry e = tab[i];
e != null;
e = tab[i = nextIndex(i, len)]) {
ThreadLocal<?> k = e.get();
// i的位置已经存在了值, 就直接替换。
if (k == key) {
e.value = value;
return;
}
//如果key==null,则进行replaceStaleEntry(替换空余的数组)
if (k == null) {
replaceStaleEntry(key, value, i);
return;
}
}
tab[i] = new Entry(key, value);
int sz = ++size;
if (!cleanSomeSlots(i, sz) && sz >= threshold)
rehash();
}
三、内存泄漏
|