`

ThreadLocal介绍

    博客分类:
  • JAVA
 
阅读更多

一、java.lang.ThreadLocal<T>

理解:

一个ThreadLocal是一个中介或者工具,来完成这样的目标,一个线程关联一个数据,在线程内共享该数据。

然后通过ThreadLocal对象,和当前线程对象,可以唯一设置一个数据,获取该数据。 

其实每一个线程内部都有一个容器ThreadLocalMap,类似于一个Map,存储key-value值。

这里的value就是数据,这里的key是ThreadLocal对象。

ThreadLocal实例 线程T1 线程T2 线程T3
tl1 tl1:value1 tl1:value1  
tl2 tl2:value2   tl2:value2

 

 

二、ThreadLocal有这样几个方法:

1.T get()

返回当前线程、当前ThreadLocal对象对应的那个数据。

实现是以ThreadLocal对象为Key去当前线程的容器map中去找数据,找到则返回;找不到则初始化一个,set进去,然后返回。

 

2.void set(T value)

给当前线程,当前ThreadLocal对象关联一个数据。

实现是以ThreadLocal对象为KEY,变量为VALUE存储到当前线程的map属性中去。

 

3.protected T initialValue()

get方法再找不到当前线程对应的变量时调用这个方法,用于初始化一个变量的值,默认是返回null。可以写一个子类继承ThreadLocal类,重写这个方法以返回需要的值。

 

4.void remove()

删除当前线程对应的变量

实现是删除map属性中当前线程的KEY-VALUE数据。

 

--------------------------------------------------------------------------------------------------------------

 

三、另一个思路实现该功能:

package tp.t1;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

public class ThreadLocal{
	//map属性,用于存储线程对象和变量的对应数据
	private Map values = Collections.synchronizedMap(new HashMap());

	//返回当前线程对应的那个变量
	public Object get(){
			Thread curThread = Thread.currentThread();
			Object o = values.get(curThread);
			if (o == null && !values.containsKey(curThread)){
				o = initialValue();
				values.put(curThread, o);
			}
			return o;
	}

	//给当前线程关联一个变量
	public void set(Object newValue){
		values.put(Thread.currentThread(), newValue);
	}
	
	//初始化一个变量的值
	public Object initialValue(){
		return null;
	}
}

 

四、测试

  • 测试1
package tp.t1;

import tp.t1.SequenceNumber;
import tp.t1.TestThread;
import java.lang.ThreadLocal;

public class Test1 {
	/*
	 * 起两个线程
	 * 每个线程给自己在ThreadLocal实例t1中关联的变量加1后显示出来,循环3次。
	 * 看看每个线程的值会不会互相影响?
	 * 答案是不会影响,每个线程关联的是自己的变量
	 */
	public static void main(String[] args){
		Thread _t1 = new TestThread();
		Thread _t2 = new TestThread();
		_t1.start();
		_t2.start();
	}
}

class SequenceNumber {
	//只需要一个ThreadLocal实例,这里定义在一个类的静态属性中,在各个线程中可以直接访问到。
	private static ThreadLocal<Integer> tl = new ThreadLocal<Integer>(){
		public Integer initialValue(){
			return 0;
		}
	};
	
	//定义一个方法,用于各个线程给自己关联的变量值加1
	public static int getNextNum(){
		SequenceNumber.tl.set(SequenceNumber.tl.get() + 1);
		return SequenceNumber.tl.get();
	}
}

class TestThread extends Thread{
	public void run(){
		for(int i = 0;i < 3;i++){
			int _num = SequenceNumber.getNextNum();
			System.out.println("Thread["+Thread.currentThread().getName()+"]-num["+_num+"]");
		}
	}
}

Thread[Thread-0]-num[1]
Thread[Thread-1]-num[1]
Thread[Thread-0]-num[2]
Thread[Thread-1]-num[2]
Thread[Thread-0]-num[3]
Thread[Thread-1]-num[3]

 

  • 测试2
package tp.t2;

import java.lang.ThreadLocal;

public class Test2 {
	/*
	 * 起两个线程
	 * 每个线程在各自关联的变量是同一个实例,这时每个线程修改实例的内容,输出实例的内容。
	 * 看看每个线程在ThreadLocal对象中,关联的变量是不是copy出来的副本,是不是会互不影响?
	 * 答案是各个线程如果关联同一个变量,那么一个线程修改变量后,另一个线程关联的变量也变化了。
	 */
	public static void main(String[] args){
		//一个ThreadLocal实例,存储的变量时AnObject类型的实例
		ThreadLocal<AnObject> _tl = new ThreadLocal<AnObject>(){
			public AnObject initialValue(){
				return new AnObject();
			}
		};
		
		//一个AnObject类型的实例
		AnObject _anObj = new AnObject();
		_anObj.s = Thread.currentThread().getName();
		
		//关联当前主线程和这个变量
		_tl.set(_anObj);
		
		System.out.println("Thread["+Thread.currentThread().getName()+"]-string["+_tl.get().s+"]");
		
		//起的第一个线程,修改变量的内容,关联变量
		Thread _t1 = new TestThread(_tl,_anObj);
		_t1.start();
		
		//起的第二个线程,修改变量的内容,关联变量
		Thread _t2 = new TestThread(_tl,_anObj);
		_t2.start();
		
		try {
			Thread.sleep(5000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		
		//输出最后这个变量的内容
		System.out.println(_anObj.s);
	}
}

class TestThread extends Thread{
	private ThreadLocal<AnObject> tl;
	private AnObject anObj;
	
	public TestThread(ThreadLocal<AnObject> _tl,AnObject _anObj){
		this.tl = _tl;
		this.anObj = _anObj;
		
		this.anObj.s = this.getName();
		
		//放在这里去关联是不可以的,因为这里的Thread.currentThread()是主线程
		//this.tl.set(this.anObj);
	}
	
	public void run(){
		//当前线程关联变量
		this.tl.set(this.anObj);
		
		System.out.println("Thread["+this.getName()+"]-string["+this.tl.get().s+"]");
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("Thread["+this.getName()+"]-string["+this.tl.get().s+"]");
	}
}

class AnObject extends Object{
	String s = "";
}

Thread[main]-string[main]
Thread[Thread-0]-string[Thread-1]
Thread[Thread-1]-string[Thread-1]
Thread[Thread-0]-string[Thread-1]
Thread[Thread-1]-string[Thread-1]
Thread-1

 

 

 

1
0
分享到:
评论

相关推荐

    ThreadLocal详解及说明

    关于线程变量ThreadLocal的介绍以及说明. 关于线程变量ThreadLocal的介绍以及说明. 关于线程变量ThreadLocal的介绍以及说明. 关于线程变量ThreadLocal的介绍以及说明. 关于线程变量ThreadLocal的介绍以及说明. ...

    Java并发编程中ThreadLocal的原理与应用分析

    通过Demo示例介绍了如何利用ThreadLocal实现线程间的隔离,使各个线程可以拥有独立的变量副本而不互相干扰。文章详细讲解了ThreadLocal中关键方法get、set、remove的操作流程,并解释了其中使用弱引用作为键的Entry...

    ThreadLocal:如何优雅的解决SimpleDateFormat多线程安全问题

    目录SimpleDateFormat诡异bug复现SimpleDateFormat诡异bug字符串日期转Date日期(parse)Date...介绍ThreadLocal使用demoThreadLocal源码探索ThreadLocal注意事项使用ThreadLocal解决SimpleDateFormat线程安全问题总结...

    Java单线程ThreadLocal串值问题解决方案

    Java单线程ThreadLocal串值问题解决方案主要介绍了Java单线程ThreadLocal串值问题解决方案,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值。 ThreadLocal简介 ThreadLocal是Java中...

    Android 中 ThreadLocal使用示例

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

    ThreadLocal 线程本地变量 及 源码分析.rar_开发_设计

    以上是对ThreadLocal的简单介绍和源码分析,实际使用中还需要结合具体业务场景进行合理设计和优化。通过深入理解ThreadLocal的工作原理,可以帮助我们更好地利用这一工具,提高代码的并发性能和可维护性。

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

    通过以上介绍,我们可以了解到 `ThreadLocal` 在处理多线程环境中提供了独特的数据隔离机制,常用于创建线程安全的工具类实例,或者在每个线程内部保存全局变量。正确使用和管理 `ThreadLocal` 是避免潜在问题的关键...

    java ThreadLocal使用案例详解

    在本文中,我们将详细介绍Java ThreadLocal的使用案例,并通过一个实际的优化案例,帮助大家理解ThreadLocal的使用。 ThreadLocal的使用场景 在Java多线程编程中,变量的线程安全是一个非常重要的问题。特别是在...

    java 中ThreadLocal 的正确用法

    下面我们将详细介绍 Java 中 ThreadLocal 的正确用法。 用法一:在关联数据类中创建 private static ThreadLocal 在 Java 中,ThreadLocal 实例通常是 private static 字段,位于希望与线程关联状态的类中。例如,...

    Java源码解析ThreadLocal及使用场景

    首先是类的介绍。ThreadLocal类提供了线程本地变量。这些变量使每个线程都有自己的一份拷贝。ThreadLocal期望能够管理一个线程的状态,例如用户id或事务id。 ThreadLocal的使用有很多优点,例如可以解决多线程间...

    ThreadLocal使用案例_动力节点Java学院整理

    本文主要介绍了ThreadLocal使用案例的分析,希望能够帮助读者更好地理解ThreadLocal的使用。 在本例中,我们需要实现一个需求,即当修改产品价格的时候,需要记录操作日志。为了实现这个需求,我们可以使用...

    关于ThreadLocal对request和response的用法说明

    主要介绍了关于ThreadLocal对request和response的用法说明,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧

    Java ThreadLocal的设计理念与作用

    主要介绍了Java ThreadLocal的设计理念与作用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

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

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

    京东一面:说出ThreadLocal的使用场景及使用方式.zip

    计算机技术、IT咨询、人工智能AI理论介绍,学习参考资料 计算机技术、IT咨询、人工智能AI理论介绍,学习参考资料 计算机技术、IT咨询、人工智能AI理论介绍,学习参考资料 计算机技术、IT咨询、人工智能AI理论介绍,...

    浅谈Java引用和Threadlocal的那些事

    本文主要介绍了Java引用和Threadlocal的知识点,包括Java中的引用类型、Threadlocal的使用等。 Java中的引用类型: Java中有四种引用类型:强引用(Strong Reference)、软引用(Soft Reference)、弱引用(Weak ...

    苍穹外卖-共享当前登录用户ID.docx

    本文将详细介绍苍穹外卖系统中如何利用`ThreadLocal`来实现在不同层次之间共享当前登录用户的ID。 #### 二、ThreadLocal简介 `ThreadLocal`是一种Java内置的线程局部变量,它为每一个使用该变量的线程都提供了一个...

Global site tag (gtag.js) - Google Analytics