转载

两分钟了解ThreadLocal机制【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());
	}
}
复制代码

未置空结果:

两分钟了解ThreadLocal机制【java线程高并发提升四】

置空且设置垃圾回收结果:

两分钟了解ThreadLocal机制【java线程高并发提升四】

2、什么是ThreadLocal?

ThreadLocal为解决多线程程序的并发问题提供了一种新的思路。使用这个工具类可以很简洁地编写出优美的多线程程序,ThreadLocal并不是一个Thread,而是Thread的局部变量。

3、ThreadLocal的应用场景及机制?

当线程A和线程B都存储到ThreadLocal里的ThreadLocalMap中,在weakReferrence引入ThreadLocal并进行对线程A,线程B操作时,线程A线程B不会互相关联、互相混淆。

两分钟了解ThreadLocal机制【java线程高并发提升四】

比如以下场景:模拟服务器处理两个用户信息。

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机制【java线程高并发提升四】

以上过程可知某线程内容全部有ThreadLocal的Threadmap托管,如果线程内容过大则很容易造成OOM问题,如何避免OOM问题呢?有以下两点:一、及时使用ThreadLocal.remove移除存储在ThreadLocalMap中不需要的线程信息,二、尽量保存较小数据在ThreadLocal中。

原文  https://juejin.im/post/5e81b5ac51882573b0472ca9
正文到此结束
Loading...