引用名称 | 引用关系 | 发生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()); } } 复制代码
未置空结果:
置空且设置垃圾回收结果:
ThreadLocal为解决多线程程序的并发问题提供了一种新的思路。使用这个工具类可以很简洁地编写出优美的多线程程序,ThreadLocal并不是一个Thread,而是Thread的局部变量。
当线程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中。