`
daibalusu
  • 浏览: 344606 次
文章分类
社区版块
存档分类
最新评论

ThreadLocal实现线程范围的共享变量

 
阅读更多

这里先说下ThreadLocal不是一个线程的本地实现版本,不是一个Thread,它是threadlocalvariable(线程局部变量);用于实现线程内的数据共享,即对于相同的程序代码,多个模块在同一个线程中运行时要共享一份数据,而在另外线程中运行时又共享另外一份数据。换一句话说就是为每一个使用该变量的线程都提供一个变量值的副本,是每一个线程都可以独立地改变自己的副本,而不会和其它线程的副本冲突。从线程的角度看,就好像每一个线程都完全拥有该变量

现做一个小练习,定义一个全局共享的ThreadLocal变量,然后启动五个线程向该ThreadLocal变量中存储一个随机值,接着各个线程调用另外其他多个类的方法,这多个类的方法中读取这个ThreadLocal变量的值,就可以看到多个类在同一个线程中共享同一份数据。

定义两个类TestATestB,用于获取值MyThreadLocal类中的X

TestA:

package com.study.threadlocal;

/**
 * 
 * @ClassName: TestA
 * @Description: 用于获取 MyThreadLocal 中变量x的值
 * @author 我夕

 */
public class TestA {
	
	public void print(){
		System.out.println(Thread.currentThread()+": TestA ,x current value is:"+MyThreadLocal.getInstance().getX());
	}
}



TestB:

package com.study.threadlocal;
/**
 * 
 * @ClassName: TestB
 * @Description: 用于获取 MyThreadLocal 中变量x的值
 * @author 我夕
 */
public class TestB {
	public void print(){
		System.out.println(Thread.currentThread()+": TestB ,x current value is:"+MyThreadLocal.getInstance().getX());
	}
}



MyThreadLocal:

package com.study.threadlocal;
/**
 * 
 * @ClassName: MyThreadLocal
 * @Description: TODO
 * @author 我夕
 */
public class MyThreadLocal {
	
	private Integer x;
	
	//将构造器声明有私有的,避免外部创建他
	private MyThreadLocal(){}
	
	private static ThreadLocal instanceThreadLocal=new ThreadLocal();//new ThreadLocal
	
	public static MyThreadLocal getInstance(){
		MyThreadLocal instance=(MyThreadLocal)instanceThreadLocal.get();
		if(instance==null){
			instance=new MyThreadLocal();
			instanceThreadLocal.set(instance);
		}
		return instance;
	}

	public Integer getX() {
		return x;
	}

	public void setX(Integer x) {
		this.x = x;
	}
	//除去线程的方法
	public static void remove(){
		instanceThreadLocal.remove();
	}

}



ThreadLocalTest

package com.study.threadlocal;

import java.util.Random;

/**
 * 
 * @ClassName: ThreadLocalTest
 * @Description: 线程局部变量练习
 * @author 我夕
 */
public class ThreadLocalTest {
	
	public static void main(String[] args) {
		
		final TestA testA=new TestA();
		final TestB testB=new TestB();
		
		//创建5个线程
		for(int i=0;i<5;i++){
			Thread thread=new Thread(new Runnable() {
				
				@Override
				public void run() {
					//生成一个随机数字给x
					MyThreadLocal.getInstance().setX(new Random().nextInt(100));
					System.out.println(Thread.currentThread()+",X current value is:"+MyThreadLocal.getInstance().getX());
					testA.print();
					testB.print();
					MyThreadLocal.getInstance().remove();

				}
			});
			thread.setName("thread_"+i);
			thread.start();
		}
		
	}
}


运行

从以上可以看出,TestATestB确实在同一个线程中共享同一份数据。

接下来,分析下ThreadLocalset()get()方法源码

set源码:

/**
* Sets the current thread's copy of this thread-local variable
* to the specified value. Most subclasses will have no need to
* override this method, relying solely on the {@link #initialValue}
* method to set the values of thread-locals.
*
* @param value the value to be stored in the current thread's copy of
* this thread-local.
*/
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}


get源码

    /**
     * Returns the value in the current thread's copy of this
     * thread-local variable.  If the variable has no value for the
     * current thread, it is first initialized to the value returned
     * by an invocation of the {@link #initialValue} method.
     *
     * @return the current thread's value of this thread-local
     */
    public T get() {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null)
                return (T)e.value;
        }
        return setInitialValue();
    }

set()get()方法,我想大家应该都知道其的作用了,set设置当前线程的线程局部变量副本的值,get返回当前线程的线程局部变量副本的值,其set方法相当于往其内部的map中增加一条记录,key分别是各自的线程,value是各自的set方法传进去的值,在线程结束时可以调用ThreadLocal.clear()方法,这样会更快释放内存,不调用也可以,因为线程结束后也可以自动释放相关的ThreadLocal变量。


分享到:
评论

相关推荐

    Java多线程编程之ThreadLocal线程范围内的共享变量

    主要介绍了Java多线程编程之ThreadLocal线程范围内的共享变量,本文讲解了ThreadLocal的作用和目的、ThreadLocal的应用场景、ThreadLocal的使用实例等,需要的朋友可以参考下

    18 线程作用域内共享变量—深入解析ThreadLocal.pdf

    Java并发编程学习宝典(漫画版),Java并发编程学习宝典(漫画版)Java并发编程学习宝典(漫画版)Java并发编程学习宝典(漫画版)Java并发编程学习宝典(漫画版)Java并发编程学习宝典(漫画版)Java并发编程学习...

    JVM的基础和调优【JMM 内存结构 GC OOM 性能调优 ThreadLocal】

    JMM 决定一个线程对共享变量的写入何时对另一个线程可见,从抽象的角度来看, JMM定义了线程和主内存之间的抽象关系:线程之间的共享变量存储在主内存(Main Memory)中, 每个线程都有一个私有的本地内存(local ...

    Java多线程与并发库高级应用视频教程22集

    【】01传统线程技术回顾【】02传统定时器技术回顾【】03传统线程互斥技术【】04传统线程同步通信技术【】04传统线程同步通信技术_分割纪录【】05线程范围内共享变量的概念与作用【】06ThreadLocal类及应用技巧【】06...

    谈谈Java中的ThreadLocal

    通过ThreadLocal可以将对象的可见范围限制在同一个线程内。  跳出误区  需要重点强调的的是,不要拿ThreadLocal和synchronized做类比,因为这种比较压根是无意义的!sysnchronized是一种互斥同步机制,是为了...

    ThreadLocal、InheritableThreadLocal详解

    多线程访问同一个共享变量时,容易出现并发冲突,为了保证线程的安全,一般使用者在访问共享变量时,需要进行适量的同步。而ThreadLocal提供了线程的私有变量,每个线程都可以通过set()和get()来对这个私有变量进行...

    java多线程安全性基础介绍.pptx

    各线程之间变量不可见,线程通信通过共享主内存实现。 volatile 仅保证可见性 作用 不会被缓存在寄存器或其他对cpu不可见的地方 强制其他线程读主内存 编译器和运行时不会讲该变量的操作与其他内存操作一起重...

    SpringBoot实现动态切换数据源(含源码)

    线程局部变量与普通的变量不同,它不是共享的,每个线程都有其自己的独立的线程局部变量副本。这使得我们可以在多线程环境中为每个线程提供独立的变量副本,从而实现线程间的数据隔离。 在数据源切换的场景中,我们...

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

    因为他可能被多个线程同时修改,此变量对于多个线程之间彼此并不独立,是共享变量。而使用ThreadLocal创建的变量只能被当前线程访问,其他线程无法访问和修改。也就是说:将线程公有化变成线程私有化。

    对ThreadLocal的理解【源码分析+应用举例】

    但是使用ThreadLocal对象去存储一个共享资源时,每一个线程的副本变量都指向同一个共享资源,这里也是会存在线程安全问题的。 ThreadLocal设计初衷:提供线程内部的局部变量,在本线程内随时随地可取,隔离其他线程...

    java面试题

    Synchronized实现内存共享,ThreadLocal为每个线程维护一个本地变量。 采用空间换时间,它用于线程间的数据隔离,为每一个使用该变量的线程提供一个副本,每个线程都可以独立地改变自己的副本,而不会和其他线程的...

    简单分析Java线程编程中ThreadLocal类的使用

    主要介绍了Java线程编程中ThreadLocal类的使用,包括使用其对共享变量的操作的分析,需要的朋友可以参考下

    springboot_mongodb

    如果如果业务逻辑强依赖于副本变量,则不适合使用ThreadLocal解决,需要另寻解决方案的局部变量,而不是为了解决共享对象的多线程访问问题。实际上,ThreadLocal根本就不能解决共享对象的多线程访问问题。 每个线程...

    Java并发编程实战

    3.3.3 ThreadLocal类 3.4 不变性 3.4.1 Final域 3.4.2 示例:使用Volatile类型来发布不可变对象 3.5 安全发布 3.5.1 不正确的发布:正确的对象被破坏 3.5.2 不可变对象与初始化安全性 3.5.3 安全发布的常用...

    Java 并发编程实战

    3.3.3 ThreadLocal类 3.4 不变性 3.4.1 Final域 3.4.2 示例:使用Volatile类型来发布不可变对象 3.5 安全发布 3.5.1 不正确的发布:正确的对象被破坏 3.5.2 不可变对象与初始化安全性 3.5.3 安全发布的常用...

    互联网创意产品众筹平台

    │ 02-ThreadLocal解决线程资源共享 │ 03-弹层组件layer使用. [- l; o" [6 F# U# ~. a7 c │ 04-用户分页查询-分析-同步请求方式 │ 05-用户分页查询-分析-同步请求代码开发 │ 06-用户分页查询-分页导航条# a1 W7 ...

    java核心知识点整理.pdf

    堆(Heap-线程共享)-运行时数据区 ...................................................................................... 23 2.2.5. 方法区/永久代(线程共享) ..................................................

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

    2.2.4. 堆(Heap-线程共享)-运行时数据区 ...................................................................................... 23 2.2.5. 方法区/永久代(线程共享) ............................................

Global site tag (gtag.js) - Google Analytics