`

ThreadLocal用法详解

 
阅读更多
转发
ThreadLocal用于保存某个线程共享变量:对于同一个static ThreadLocal,不同线程只能从中get,set,remove自己的变量,而不会影响其他线程的变量。
1、ThreadLocal.get: 获取ThreadLocal中当前线程共享变量的值。
2、ThreadLocal.set: 设置ThreadLocal中当前线程共享变量的值。
3、ThreadLocal.remove: 移除ThreadLocal中当前线程共享变量的值。
4、ThreadLocal.initialValue: ThreadLocal没有被当前线程赋值时或当前线程刚调用remove方法后调用get方法,返回此方法值。

ThraedLocal = copy value into every Thread
示例:
package com.anker.thread;

public class MyThreadLocal {
	private static final ThreadLocal<Object> threadLocal = new ThreadLocal<Object>() {
		/**
		 * 
		 * ThreadLocal没有被当前线程赋值时或当前线程刚调用remove方法后调用get方法,返回此方法值
		 * 
		 */
		@Override
		protected Object initialValue()
		{
			System.out.println("调用get方法时,当前线程共享变量没有设置,调用initialValue获取默认值!");
			return null;
		}
	};
	public static void main(String[] args)
	{
		new Thread(new MyIntegerTask("IntegerTask1")).start();
		try {
			Thread.sleep(2000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		new Thread(new MyIntegerTask("IntegerTask2")).start();
//		new Thread(new MyStringTask("StringTask1")).start();
//		new Thread(new MyStringTask("StringTask2")).start();
	}

	public static class MyIntegerTask implements Runnable {
		private String name;
		MyIntegerTask(String name) {
			this.name = name;
		}
		@Override
		public void run() {
			for (int i = 0; i < 5; i++) {
				// ThreadLocal.get方法获取线程变量
				if (null == MyThreadLocal.threadLocal.get()) {
					// ThreadLocal.et方法设置线程变量
					MyThreadLocal.threadLocal.set(0);
					System.out.println("线程" + name + ": 0");
				} else {
					int num = (Integer) MyThreadLocal.threadLocal.get();
					MyThreadLocal.threadLocal.set(num + 1);
					System.out.println("线程" + name + ": "+ MyThreadLocal.threadLocal.get());
					if (i == 3) {
						MyThreadLocal.threadLocal.remove();
					}
				}
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
	}
	public static class MyStringTask implements Runnable {
		private String name;
		MyStringTask(String name) {
			this.name = name;
		}
		@Override
		public void run() {
			for (int i = 0; i < 5; i++) {
				if (null == MyThreadLocal.threadLocal.get()) {
					MyThreadLocal.threadLocal.set("a");
					System.out.println("线程" + name + ": a");
				} else {
					String str = (String) MyThreadLocal.threadLocal.get();
					MyThreadLocal.threadLocal.set(str + "a");
					System.out.println("线程" + name + ": "+ MyThreadLocal.threadLocal.get());
				}
				try {
					Thread.sleep(800);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
	}
}
Thread.ThreadLocalMap<ThreadLocal, Object>;
1、Thread: 当前线程,可以通过Thread.currentThread()获取。
2、ThreadLocal:我们的static ThreadLocal变量。
3、Object: 当前线程共享变量。

我们调用ThreadLocal.get方法时,实际上是从当前线程中获取ThreadLocalMap<ThreadLocal, Object>,然后根据当前ThreadLocal获取当前线程共享变量Object。
ThreadLocal.set,ThreadLocal.remove实际上是同样的道理。

这种存储结构的好处:
1、线程死去的时候,线程共享变量ThreadLocalMap则销毁。
2、ThreadLocalMap<ThreadLocal,Object>键值对数量为ThreadLocal的数量,一般来说ThreadLocal数量很少,相比在ThreadLocal中用Map<Thread, Object>键值对存储线程共享变量(Thread数量一般来说比ThreadLocal数量多),性能提高很多。

关于ThreadLocalMap<ThreadLocal, Object>弱引用问题:
当线程没有结束,但是ThreadLocal已经被回收,则可能导致线程中存在ThreadLocalMap<null, Object>的键值对,造成内存泄露。(ThreadLocal被回收,ThreadLocal关联的线程共享变量还存在)。
虽然ThreadLocal的get,set方法可以清除ThreadLocalMap中key为null的value,但是get,set方法在内存泄露后并不会必然调用,所以为了防止此类情况的出现,我们有两种手段。
1、使用完线程共享变量后,显示调用ThreadLocalMap.remove方法清除线程共享变量;
2、JDK建议ThreadLocal定义为private static,这样ThreadLocal的弱引用问题则不存在了。

 

 

分享到:
评论

相关推荐

    ThreadLocal 用法详解.md

    ThreadLocal 用法详解.md

    Java ThreadLocal用法实例详解

    主要介绍了Java ThreadLocal用法,结合实例形式详细分析了ThreadLocal线程局部变量相关原理、定义与使用方法,需要的朋友可以参考下

    java 中ThreadLocal 的正确用法

    主要介绍了java 中ThreadLocal 的正确用法的相关资料,需要的朋友可以参考下

    JAVA开发常用类库UUID、Optional、ThreadLocal、TimerTask、Base64使用方法与实例详解

    主要介绍了JAVA开发常用类库UUID、Optional、ThreadLocal、TimerTask、Base64使用方法与实例详解,需要的朋友可以参考下

    Android 中 ThreadLocal使用示例

    主要介绍了Android 中 ThreadLocal使用示例的相关资料,这里提供示例代码帮助大家学习理解这部分内容,需要的朋友可以参考下

    汪文君高并发编程实战视频资源下载.txt

    │ 高并发编程第二阶段26讲、ThreadLocal使用详解,深入原理介绍.mp4 │ 高并发编程第二阶段27讲、多线程运行上下文设计模式介绍.mp4 │ 高并发编程第二阶段28讲、使用ThreadLocal重新实现一个上下文设计模式.mp4...

    Java 高并发九:锁的优化和注意事项详解

    本文主要介绍Java高并发锁的优化和注意事项,这里整理了详细的资料,并讲解了 1. 锁优化的思路和方法 2. 虚拟机内的锁优化 3. 一个错误使用锁的案例 4. ThreadLocal及其源码分析等知识,有需要的小伙伴可以参考下

    Spring.3.x企业应用开发实战(完整版).part2

    《Spring3.x企业应用开发实战》是在《精通Spring2.x——企业应用开发详解》的基础上,经过历时一年的重大调整改版而成的,本书延续了上一版本追求深度,注重原理,不停留在技术表面的写作风格,力求使读者在熟练使用...

    Spring3.x企业应用开发实战(完整版) part1

    《Spring3.x企业应用开发实战》是在《精通Spring2.x——企业应用开发详解》的基础上,经过历时一年的重大调整改版而成的,本书延续了上一版本追求深度,注重原理,不停留在技术表面的写作风格,力求使读者在熟练使用...

    JAVA核心知识点整理(有效)

    2.2.3. 本地方法区(线程私有) ................................................................................................................ 23 2.2.4. 堆(Heap-线程共享)-运行时数据区 .....................

    汪文君高并发编程实战视频资源全集

    │ 高并发编程第二阶段26讲、ThreadLocal使用详解,深入原理介绍.mp4 │ 高并发编程第二阶段27讲、多线程运行上下文设计模式介绍.mp4 │ 高并发编程第二阶段28讲、使用ThreadLocal重新实现一个上下文设计模式.mp4...

    疯狂JAVA讲义

    5.2 方法详解 116 5.2.1 方法的所属性 116 5.2.2 方法的参数传递机制 116 5.2.3 形参长度可变的方法 120 5.2.4 递归方法 121 5.2.5 方法重载 123 学生提问:为什么方法的返回值类型不能用于区分重载的方法? ...

    Spring API

    使用@RequestParam绑定请求参数到方法参数 13.12.5. 使用@ModelAttribute提供一个从模型到数据的链接 13.12.6. 使用@SessionAttributes指定存储在会话中的属性 13.12.7. 自定义WebDataBinder初始化 13.13. 更多...

    Spring中文帮助文档

    使用@RequestParam绑定请求参数到方法参数 13.12.5. 使用@ModelAttribute提供一个从模型到数据的链接 13.12.6. 使用@SessionAttributes指定存储在会话中的属性 13.12.7. 自定义WebDataBinder初始化 13.13. 更多...

    Spring 2.0 开发参考手册

    3.3.3. bean属性及构造器参数详解 3.3.4. 使用depends-on 3.3.5. 延迟初始化bean 3.3.6. 自动装配(autowire)协作者 3.3.7. 依赖检查 3.3.8. 方法注入 3.4. bean的作用域 3.4.1. Singleton作用域 3.4.2. ...

    spring chm文档

    3.3.3. bean属性及构造器参数详解 3.3.4. 使用depends-on 3.3.5. 延迟初始化bean 3.3.6. 自动装配(autowire)协作者 3.3.7. 依赖检查 3.3.8. 方法注入 3.4. bean的作用域 3.4.1. Singleton作用域 3.4.2. ...

    Spring-Reference_zh_CN(Spring中文参考手册)

    3.3.3. bean属性及构造器参数详解 3.3.3.1. 直接量(基本类型、Strings类型等。) 3.3.3.2. 引用其它的bean(协作者) 3.3.3.3. 内部bean 3.3.3.4. 集合 3.3.3.5. Nulls 3.3.3.6. XML-based configuration metadata ...

    java面试题,180多页,绝对良心制作,欢迎点评,涵盖各种知识点,排版优美,阅读舒心

    【基础】Java 中的final关键字有哪些用法? 31 【基础】内部类可以引用它的包含类(外部类)的成员吗?有没有什么限制? 31 【基础】I/O总结 31 【基础】Java中如何实现序列化,有什么意义? 34 【WEB】session与...

Global site tag (gtag.js) - Google Analytics