TheadLocal 原理及实践

目录

ThreadLocal

实现原理

使用场景

使用实例


ThreadLocal

         线程本地存储,为变量在每个线程中都创建一个副本(在Thread中存储以ThreadLocal为key的值),每个线程可以访问自己内部的副本变量。

实现原理

         ThreadLocal内部用ThreadLocalMap来存储变量值,实际上线程本地变量存储在Thread类的threadLocals ;变量中,做以下说明。

  • get操作.首先获取当前线程,从当前线程中获取ThreadLocalMap对象,进而获取以ThreadLocal为key的value值并返回。

  • 关于ThreadLocalMap,是在ThreadLocal对象中定义的,作为Thread类的属性,本质上是一个数组列表,且列表的元素[Entry]都是WeakReference[虚引用]的子类,意味着ThreadLocal中存储的成员在没有外部引用的情况下会被垃圾收集回收。

 

使用场景

         并发场景下通过让不同线程持有相同资源的不同副本来避免线程安全问题,也可以用来提高系统并发性能。

         与线程池相比,更容易封装,更容易从底层屏蔽掉多线程模型。同时不受控制的线程数量可能会带来资源耗尽。

         常见的使用ThreadLocal来进行线程本地绑定一些非线程安全的对象(如网络客户端,读写客户端等等),并允许这些对象被垃圾收集机制回收,回收后允许进行再次绑定。

使用实例

         FastDFS的StorageClient是非线程安全的。在进行大批量数据上传的时候单个StorageClient无法满足性能要求。

public class FDFSUtil {
	private static Log log = LogFactory.getLog(FDFSUtil.class);
	private static volatile ThreadLocal<StorageClient> threadLocal = new ThreadLocal<>();
	private static final String DEFAULT_FILE_EXT_NAME = "jpg";

	public String[] upload(byte[] image) {
		try {
			long start = System.currentTimeMillis();
			String values[] = getClient().upload_file(image, DEFAULT_FILE_EXT_NAME, null);
			long end = System.currentTimeMillis();
			log.debug("UPLOAD FILE SUCCESS USE TIME:" + (end - start) + ",RESULT:" + Arrays.asList(values));
			return values;
		} catch (Exception e) {
			log.error(e);
			return null;
		}
	}

	public String[] upload(byte[] image, String fileExtName) {
		try {
			long start = System.currentTimeMillis();
			String values[] = getClient().upload_file(image, fileExtName, null);
			long end = System.currentTimeMillis();
			log.debug("UPLOAD FILE SUCCESS USE TIME:" + (end - start) + ",RESULT:" + Arrays.asList(values));
			return values;
		} catch (Exception e) {
			log.error(e);
			return null;
		}
	}

	public byte[] download(String group, String path) {
		try {
			long start = System.currentTimeMillis();
			byte[] image = getClient().download_file(group, path);
			long end = System.currentTimeMillis();
			log.debug("DOWNLOAD FILE SUCCESS USE TIME:" + (end - start));
			return image;
		} catch (Exception e) {
			e.printStackTrace();
			log.error(e);
		}
		return null;
	}

	public StorageClient getClient() {
		if (threadLocal.get() == null) {
			synchronized (threadLocal) {
				if (threadLocal.get() == null) {
					threadLocal.set(new StorageClient(null, null));
				}
			}
		}
		return threadLocal.get();
	}
}

 

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值