`

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 ThreadLocal用法实例详解 Java ThreadLocal是Java中的一种线程局部变量机制,用于保存每个线程独有的数据,以避免线程之间的数据共享问题。ThreadLocal的基本使用非常简单,只需要定义一个ThreadLocal变量,...

    Java 中ThreadLocal类详解

    `initialValue`方法是ThreadLocal的一个重要方法,它是一个保护方法,在每个线程第一次访问该变量时调用,返回该线程的初始值。在这个例子中,随机生成一个0到10000之间的整数作为初始值。 `Accessor`类实现了...

    java ThreadLocal使用案例详解

    Java ThreadLocal使用案例详解 Java ThreadLocal是Java语言中的一种机制,用于为每个线程提供一个独立的变量副本,以解决多线程环境下共享变量的线程安全问题。在本文中,我们将详细介绍Java ThreadLocal的使用案例...

    ThreadLocal详解

    #### ThreadLocal的接口方法详解 ThreadLocal类提供了以下四个主要的接口方法: 1. `void set(Object value)`:用于设置当前线程的线程局部变量的值。这意味着每个线程可以独立地设置和修改自己的变量副本,而不...

    2、导致JVM内存泄露的ThreadLocal详解

    ### 导致JVM内存泄露的ThreadLocal详解 #### 一、为什么要有ThreadLocal 在多线程编程中,为了避免线程间的数据竞争和保证线程安全性,常常需要使用同步机制如`synchronized`来控制线程对共享资源的访问。然而,...

    ThreadLocal

    ### ThreadLocal核心概念详解 #### 一、ThreadLocal简介与重要性 ThreadLocal是一个非常重要的Java并发工具类,它的核心概念在于为每一个线程提供了一个独立的变量副本,从而避免了线程之间的数据竞争问题。这使得...

    Java资料-详解ThreadLocal

    为了避免这种情况,建议在不再需要使用`ThreadLocal`时,使用`remove()`方法清理。 总之,`ThreadLocal`是Java中用于创建线程局部变量的一个工具,它使得我们可以在线程之间隔离变量,避免并发问题,提高程序的...

    java 中ThreadLocal 的正确用法

    * 在使用 ThreadLocal 时,需要确保 initialValue() 方法的正确实现,以避免线程之间的数据共享。 * 在使用 ThreadLocal 时,需要注意避免内存泄漏的问题,例如,在使用完毕后,需要将 ThreadLocal 变量设置为 null...

    java核心知识点学习----多线程间的数据共享和对象独立,ThreadLocal详解.pdf

    在上述代码中,创建了一个ThreadLocal实例,然后在线程的run()方法中设置值,每个线程设置的数据只对自己可见,不会影响其他线程。这样既实现了数据共享(所有线程可以访问到ThreadLocal),又确保了对象独立(每个...

    Java 并发编程之ThreadLocal详解及实例

    下面将详细探讨 ThreadLocal 的工作原理、使用方法以及适用场景。 1. **ThreadLocal 工作原理** - 每个 `ThreadLocal` 实例在每个线程中都有一个对应的存储槽,这个存储槽存储的是变量的副本。当创建一个新的 `...

    ThreadLocal、InheritableThreadLocal详解

    当使用ThreadLocal的set()方法设置值时,实际上是将值放入当前线程的ThreadLocalMap中,而get()方法则从该线程的ThreadLocalMap中获取值。因此,不同线程访问同一个ThreadLocal实例时,它们看到的是各自的副本,互不...

    Synchronized与ThreadLocal

    #### 二、ThreadLocal机制详解 **ThreadLocal** 提供了一种线程本地存储的解决方案,为每个线程创建独立的副本,避免了线程间的共享和争用问题。 - **作用原理:** - ThreadLocal 维护了一个 Map 结构,其中 Key ...

    JAVA ThreadLocal类深入

    ### 二、ThreadLocal API详解 1. `ThreadLocal()`:创建一个新的线程局部变量。 2. `T get()`:返回当前线程的ThreadLocal变量副本中的值,如果这是线程第一次调用get(),则初始化副本。 3. `protected T initial...

    8个案例详解教会你ThreadLocal.docx

    - 多个开源框架如 Spring、Hibernate 都使用了 `ThreadLocal`。例如,Spring 中的 TransactionTemplate 和 AOP 模块利用 `ThreadLocal` 存储当前事务信息,Hibernate 中的 Session 管理也依赖于 `ThreadLocal` 来...

    java线程本地变量ThreadLocal详解

    Java 线程本地变量 ThreadLocal 详解 ThreadLocal 是 Java 中的一个类,提供了线程安全的对象封装,用于解决多线程访问数据的冲突问题。ThreadLocal 的主要目的是为每个线程提供一个变量副本,从而隔离了多个线程...

    Android 中 ThreadLocal使用示例

    下面将详细介绍ThreadLocal的工作原理、使用方法以及在Android中的实际应用。 ### 1. ThreadLocal工作原理 ThreadLocal内部实现了一个HashMap,用于存储每个线程与对应的变量副本之间的映射关系。当我们创建一个新...

    理解ThreadLocal

    ThreadLocal 详解 ThreadLocal 是 Java 中一个非常重要的类,它为解决多线程程序的并发问题提供了一种新的思路。ThreadLocal 并不是一个 Thread,而是 Thread 的局部变量,它为每个使用该变量的线程提供独立的变量...

Global site tag (gtag.js) - Google Analytics