juc基础之Threadlocal
Threadlocal底层原理
-
get方法源码
-
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
} -
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
-
-
get源码分析
-
获取当前线程
-
获取当前线程内部的threadLocals,即一个ThreadlocalMap
-
以当前Threadlocal对象为key,从threadLocals中取出Entry
-
返回Entry的value属性
-
-
set方法源码
-
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
map.set(this, value);
} else {
createMap(t, value);
}
} -
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
-
-
set源码分析
- 获取当前线程
- 获取当前线程内部的threadLocals,即一个即一个ThreadlocalMap
- 以当前Threadlocal对象为key,向threadLocals中存入value
强,软,弱,虚引用
-
强引用
内存不足时,jvm开始进行gc,对于强引用对象,就算出现了oom也不会对该对象进行回收,死都不会回收
-
public class demo {
public static void main(String[] args) {
//强引用
Object o1 = new Object();
//模拟内存不足
try {
byte[] bytes = new byte[30*1024*1024];
} catch (Exception e){
}
//系统进行垃圾回收
System.gc();
//强引用不会被回收
System.out.println(o1);
}
}
-
-
软引用
内存充足时,不会被回收,内存不足时,就会被回收
-
-Xms5m -Xmx5m -XX:+PrintGCDetails
-
public class demo {
public static void main(String[] args) {
//弱引用
WeakReference<String> stringWeakReference = new WeakReference<String>("ok");
//系统进行垃圾回收
System.gc();
//弱引用不会被回收
System.out.println(stringWeakReference);
}
}
-
-
弱引用
只要gc,就会被回收
-
public class demo {
public static void main(String[] args) {
Object o1 = new Object();
//弱引用
System.out.println(o1);
WeakReference<Object> objectSoftReference = new WeakReference<>(o1);
System.out.println(objectSoftReference);
o1=null;
//系统进行gc
System.gc();
System.out.println("---------------");
System.out.println(o1);
System.out.println(objectSoftReference.get());
}
}
-
内存泄漏
内存泄漏:申请了内存,但是该内存一直无法释放
补充:
内存溢出:发现申请内存不足,就会报错,内存溢出的问题
-
为什么会产生内存泄漏问题?
ThreadLocalMap
使用ThreadLocal
的弱引用作为key
,如果一个ThreadLocal
没有外部强引用来引用它,那么系统 GC 的时候,这个ThreadLocal
势必会被回收这样一来,ThreadLocalMap
中就会出现key
为null
的Entry
,就没有办法访问这些key
为null
的Entry
的value
,如果当前线程再迟迟不结束的话,这些Entry永远无法回收,造成内存泄漏
-
内存泄漏-代码实现
-
public class demo {
public static void main(String[] args) {
MyExecutor myExecutor = new MyExecutor();
for (int i = 0; i < 100; i++) {
final int finalI = i;
myExecutor.execute(()->{
ThreadLocal<String> stringThreadLocal = new ThreadLocal<>();
stringThreadLocal.set(""+finalI);
});
}
myExecutor.execute(()->{
Thread thread = Thread.currentThread();
ThreadLocal<String> stringThreadLocal = new ThreadLocal<>();
stringThreadLocal.set("ok");
});
}
}
class MyExecutor{
private ArrayList<Runnable> threadPool = new ArrayList<>();
private LinkedBlockingQueue<Runnable> task =new LinkedBlockingQueue<>();
public MyExecutor() {
for (int i = 0; i < 2; i++) {
Thread thread = new Thread(() -> {
while (true) {
Runnable runnable = task.poll();
if (runnable != null) {
runnable.run();
}
}
});
thread.start();
threadPool.add(thread);
}
}
public boolean execute(Runnable runnable){
return task.offer(runnable);
}
}
-
-
如何避免内存泄漏问题
-
get/set方法,会检测key=null的entry并删除
-
get
-
private Entry getEntryAfterMiss(ThreadLocal<?> key, int i, Entry e) {
Entry[] tab = table;
int len = tab.length;
while (e != null) {
ThreadLocal<?> k = e.get();
if (k == key)
return e;
if (k == null)
expungeStaleEntry(i);
else
i = nextIndex(i, len);
e = tab[i];
}
return null;
} -
set
-
for (Entry e = tab[i];
e != null;
e = tab[i = nextIndex(i, len)]) {
ThreadLocal<?> k = e.get();
if (k == key) {
e.value = value;
return;
}
if (k == null) {
replaceStaleEntry(key, value, i);
return;
}
}
-
-
使用完Threadlocal后,要remove掉
-
-
为什么是弱引用,不是强引用
- key 使用强引用:引用的
ThreadLocal
的对象被回收了,但是ThreadLocalMap
还持有ThreadLocal
的强引用,如果没有手动删除,ThreadLocal
不会被回收,导致Entry
内存泄漏 - key 使用弱引用:引用的
ThreadLocal
的对象被回收了,由于ThreadLocalMap
持有ThreadLocal
的弱引用,即使没有手动删除,ThreadLocal
也会被回收。value
在下一次ThreadLocalMap
调用set
,get
的时候会被清除 - 使用弱引用可以多一层保障:弱引用
ThreadLocal
不会内存泄漏,对应的value
在下一次ThreadLocalMap
调用set
,get
,remove
的时候会被清除
- key 使用强引用:引用的
标签:ThreadLocal,threadlocal,源码,引用,key,null,public,详解,内存 From: https://www.cnblogs.com/new228666/p/16867867.html