线程----ThreadLocal数据机构、实现原理、误用引起的OOM问题

java四种引用关系

线程----ThreadLocal数据机构、实现原理、误用引起的OOM问题_第1张图片

这里需要用到弱引用,从图中可以看出,只要对象无关联就会被回收
public class WeakReferenceTest {
	/*
	 * 测试WeakReference,WeakReference引用的对象并没有被其他对象直接应用
	 */
	
	private static void testWeakReferenceNoDirectReference() throws Exception{
		Object obj=new Object();
		WeakReference<Object> weakRef=new WeakReference<>(obj);
		System.out.println(weakRef.get());
		
		obj=null;
		System.gc();
		Thread.sleep(3000);
		System.out.println(weakRef.get());
	}
	
	public static void main(String[] args) {
		try {
			testWeakReferenceNoDirectReference();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

结果:

java.lang.Object@15db9742
null
  • 可以看出对象如果没有关联就会被回收
public class WeakReferenceTest {
	/*
	 * 测试WeakReference,WeakReference引用的对象有被其他对象直接应用
	 */
	
	private static void testWeakReferenceNoDirectReference() throws Exception{
		Object obj=new Object();
		WeakReference<Object> weakRef=new WeakReference<>(obj);
		System.out.println(weakRef.get());
		
		List<Object> objectList=new ArrayList();
		objectList.add(obj);
		
		obj=null;
		
		System.gc();
		Thread.sleep(3000);
		System.out.println(weakRef.get());
	}
	
	public static void main(String[] args) {
		try {
			testWeakReferenceNoDirectReference();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

结果:

java.lang.Object@15db9742
java.lang.Object@15db9742
  • obj有被关联,所以置空前后对象都存在

ThreadLocal数据结构

线程----ThreadLocal数据机构、实现原理、误用引起的OOM问题_第2张图片
ThreadLocals是依附在Thread对象的一个成员变量,ThreadLocals对应的类是ThreadLocal里的ThreadLocalMap,ThreadLocalMap与我们常用的HashMap类似,它是由Entry组成的table数组(private Entry[] table;),这个数组Entry的key就是WeakReference,value就是ThreadLocal的一个对象
线程----ThreadLocal数据机构、实现原理、误用引起的OOM问题_第3张图片
每个线程对象都有自己的threadLocals,他们的threadLocals值是不会相互干扰的,这也是ThreadLocal能获得自己的一个成员变量,去拿到自己的值,而不会交错、混淆拿到其他线程的值,这也是ThreadLocal在线程高并发提供一个好的方案

ThreadLocal实现原理

public class UserSessionContext {
	
	private static ThreadLocal<UserSessionContext> threadLocal=ThreadLocal.withInitial(UserSessionContext::new);
	
	public static UserSessionContext getUserSessionContext(){
		return threadLocal.get();
	}
	
	public static void removeContext(){
		threadLocal.remove();
	}
	
	private Long userId;

	public Long getUserId() {
		return userId;
	}

	public void setUserId(Long userId) {
		System.out.println(Thread.currentThread().getName()+"set userId="+userId);
		this.userId = userId;
	}
}
public class HTTPTest {
    public static void main(String[] args) {
    	/*
    	 * 模拟场景:HTTP服务端使用多线程处理来自不同用户的请求
    	 */
        sampleTest();
    }

    private static void sampleTest() {
        ExecutorService executorService = Executors.newFixedThreadPool(2);

        executorService.submit(new Runnable() {
            public void run() {
                Long userId = 10000L;
                doUseRequest(userId);
            }
        });

        executorService.submit(new Runnable() {
                public void run() {
                    Long userId = 20000L;
                    doUseRequest(userId);
                }
        });
    }
        private static void doUseRequest(Long userId){
        	UserSessionContext.getUserSessionContext().setUserId(userId);

            String info = getMyInfo();
            List<String> courses = getMyCourses();
    System.out.println(Thread.currentThread().getName()+"info="+info+";courses="+JSONObject.toJSONString(courses));
        
        UserSessionContext.removeContext();
        }
        
        
        private static String getMyInfo (){
            return UserSessionContext.getUserSessionContext().getUserId()+"的个人信息";
        }
        private static List<String> getMyCourses (){
            return Collections.singletonList(UserSessionContext.getUserSessionContext().getUserId()+"的java并发基础课程");
        }
}

线程----ThreadLocal数据机构、实现原理、误用引起的OOM问题_第4张图片

ThreadLocal引起的OOM问题

线程----ThreadLocal数据机构、实现原理、误用引起的OOM问题_第5张图片

ThreadLocal OOM问题避免

  • 在使用ThreadLocal时,都要在线程全部执行完之后在finally代码块中调用remove()方法,清除内存(线程池中使用尤为注意)
  • 保存在ThreadLocal的数据不要太大

你可能感兴趣的:(线程)