1、java的四种引用。
引用名称 | 引用关系 | 发生GC(垃圾回收)时 | 发生OOM(内存溢出)前 | 回收条件 |
---|---|---|---|---|
StrongReference(强引用) | 1.强 | 不回收 | 不回收 | 无关联引用 |
SoftReference(软引用) | 1.软 | 不回收 | 回收 | 无关联引用且内存不足 |
WeakReference(弱引用) | 3.弱 | 回收 | 回收 | 无关联引用或置空 |
PhantomReference(虚引用) | 4.虚 | 回收 | 回收 | 任意时间 |
比如:以下例子中,当弱引用对象weak被置空并且gc之后,引用对象object才会被回收。
package Four_ThreadLocal;
import java.lang.ref.WeakReference;
public class Thread_Reference {
public static void main(String[] args) throws InterruptedException {
Object object = new Object();
WeakReference<Object> weakReference = new WeakReference<>(object);
System.out.println("垃圾回收前,获取对象:"+weakReference.get());
object =null;
//弱引用gc(垃圾回收)
System.gc();
//设置垃圾清理最长时间
Thread.sleep(1000);
System.out.println("垃圾回收后,获取对象:"+weakReference.get());
}
}
复制代码
未置空结果:
置空且设置垃圾回收结果:2、什么是ThreadLocal?
ThreadLocal为解决多线程程序的并发问题提供了一种新的思路。使用这个工具类可以很简洁地编写出优美的多线程程序,ThreadLocal并不是一个Thread,而是Thread的局部变量。
3、ThreadLocal的应用场景及机制?
当线程A和线程B都存储到ThreadLocal里的ThreadLocalMap中,在weakReferrence引入ThreadLocal并进行对线程A,线程B操作时,线程A线程B不会互相关联、互相混淆。
比如以下场景:模拟服务器处理两个用户信息。package Four_ThreadLocal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import com.sun.xml.internal.bind.v2.schemagen.xmlschema.List;
public class Thread_ThreadLocal {
public static void main(String[] args) {
simtest();
}
private static void simtest() {
// TODO Auto-generated method stub
ExecutorService newFixedThreadPool = Executors.newFixedThreadPool(2);
newFixedThreadPool.submit(()->{
Long userId = 1000L;
douserReq(userId);
});
newFixedThreadPool.submit(()->{
Long userId = 2000L;
douserReq(userId);
});
}
private static void douserReq(long userId) {
// TODO Auto-generated method stub
UserSessionContext.getUserSessionContext().setUserId(userId);
//获取当前进程信息
String info = getMyCourses();
System.out.println(Thread.currentThread().getName()+"的信息是:"+info);
UserSessionContext.removeContext();
}
private static String getMyCourses() {
// TODO Auto-generated method stub
return UserSessionContext.getUserSessionContext().getUserId()+"信息";
}
public static class UserSessionContext{
private static ThreadLocal<UserSessionContext> threadLocal =
ThreadLocal.withInitial(UserSessionContext::new);
private Long UserId;
public Long getUserId() {
return UserId;
}
public void setUserId(Long userId) {
System.out.println(Thread.currentThread().getName()+"记录:"+userId);
this.UserId = userId;
}
public static UserSessionContext getUserSessionContext() {
return threadLocal.get();
}
public static void removeContext() {
threadLocal.remove();
}
}
}
复制代码
将两个线程的信息利用UserSessionContext存储到ThreadLoca对应的ThreadLocalMapl中,线程信息获取时调用Thread.get,获取当前线程的信息通过Threadmap匹配到内容,就将该线程的内容准确的调取出来了,结果展示如下:
以上过程可知某线程内容全部有ThreadLocal的Threadmap托管,如果线程内容过大则很容易造成OOM问题,如何避免OOM问题呢?有以下两点:一、及时使用ThreadLocal.remove移除存储在ThreadLocalMap中不需要的线程信息,二、尽量保存较小数据在ThreadLocal中。