博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
ThreadLocal
阅读量:6916 次
发布时间:2019-06-27

本文共 3053 字,大约阅读时间需要 10 分钟。

一、定义

  翻译成中文应该叫做线程局部变量。这个类到底有什么用处呢?在并发编程的时候,成员变量如果不做任何处理其实是线程不安全的,各个线程都在操作同一个变量,显然是不行的,并且我们也知道volatile这个关键字也是不能保证线程安全的。那么在有一种情况之下,我们需要满足这样一个条件:变量是同一个,但是每个线程都使用同一个初始值,也就是使用同一个变量的一个新的副本。这种情况之下ThreadLocal就非常有用,比如说DAO的数据库连接,我们知道DAO是单例的,那么他的属性Connection就不是一个线程安全的变量。而我们每个线程都需要使用他,并且各自使用各自的。这种情况,ThreadLocal就比较好的解决了这个问题。

简单的说:线程局部变量(ThreadLocal)其实的功用非常简单,就是为每一个使用该变量的线程都提供一个变量值的副本,是Java中一种较为特殊的线程绑定机制,是每一个线程都可以独立地改变自己的副本,而不会和其它线程的副本冲突。

二、构造方法和方法

  

三、举例子说明作用

  1、创建一个TestThreadLocal类

    

public class TestThreadLocal {	public static void main(String[] args) {		ThreadLocal tl = new ThreadLocal();		tl.set("p");				MyThread mt = new MyThread(tl);		mt.start();				System.out.println(tl.get());	}}

   2、创建一个MyThread类,开启另一个线程

    

public class MyThread extends Thread{	private ThreadLocal tl;	public MyThread(ThreadLocal tl) {		this.tl = tl;	}	@Override	public void run() {		System.out.println(tl.get()+"aaaaaaaaaaaa");	}	}

   3、运行结果

  4、分析:

    当t1这边的线程开启后,将t1中存放p。之后再Tread中开启另一个线程。使用构造方法将t1传入到Thread中,但是发现没有办法取到t1中的值。

四、在JDBC中使用

  

public class ConnectionUtil {    private static ThreadLocal
tl = new ThreadLocal
(); private static Connection initConn = null; static { try { initConn = DriverManager.getConnection("url, name and password"); } catch (SQLException e) { e.printStackTrace(); } } public Connection getConn() { Connection c = tl.get(); if(null == c) tl.set(initConn); return tl.get(); } }

这样保证了都是用同一个连接,但是每个连接都是新的,是同一个连接的副本。

五、实现机制

  1、每个Thread对象内部都维护了一个ThreadLocalMap这样一个ThreadLocal的Map,可以存放若干个ThreadLocal。

ThreadLocal.ThreadLocalMap threadLocals = null;

 

  2、当我们在调用get()方法的时候,先获取当前线程,然后获取到当前线程的ThreadLocalMap对象,如果非空,那么取出ThreadLocal的value,否则进行初始化,初始化就是将initialValue的值set到ThreadLocal中。

1 public T get() { 2     Thread t = Thread.currentThread(); 3     ThreadLocalMap map = getMap(t); 4     if (map != null) { 5         ThreadLocalMap.Entry e = map.getEntry(this); 6         if (e != null) 7             return (T)e.value; 8     } 9     return setInitialValue();10 }

 

  3、当我们调用set()方法的时候,很常规,就是将值设置进ThreadLocal中。

  4、总结:当我们调用get方法的时候,其实每个当前线程中都有一个ThreadLocal。每次获取或者设置都是对该ThreadLocal进行的操作,是与其他线程分开的。

  5、应用场景:当很多线程需要多次使用同一个对象,并且需要该对象具有相同初始化值的时候最适合使用ThreadLocal。

  6、其实说再多也不如看一下源码来得清晰。如果要看源码,其中涉及到一个WeakReference和一个Map,这两个地方需要了解下,这两个东西分别是a.Java的弱引用,也就是GC的时候会销毁该引用所包裹(引用)的对象,这个threadLocal作为key可能被销毁,但是只要我们定义成他的类不卸载,tl这个强引用就始终引用着这个ThreadLocal的,永远不会被gc掉。b.和HashMap差不多。

  事实上,从本质来讲,就是每个线程都维护了一个map,而这个map的key就是threadLocal,而值就是我们set的那个值,每次线程在get的时候,都从自己的变量中取值,既然从自己的变量中取值,那肯定就不存在线程安全问题,总体来讲,ThreadLocal这个变量的状态根本没有发生变化,他仅仅是充当一个key的角色,另外提供给每一个线程一个初始值。如果允许的话,我们自己就能实现一个这样的功能,只不过恰好JDK就已经帮我们做了这个事情。

  

public class ThreadLocal{private Map
container = new HashMap
();public void set(Object value){container.put(Thread.currentThread(),value);//用当前线程作为key}public Object get(){return container.get(Thread.currentThread());}public void remove(){container.remove(Thread.currentThread());}}总结:调用该类的get方法,永远返回当前线程放入的数据。线程局部变量。

 

转载地址:http://tmxcl.baihongyu.com/

你可能感兴趣的文章
TP 接收post请求使用框架自带函数I()防止注入
查看>>
WCF学习总结
查看>>
Android Studio项目转Eclipse项目
查看>>
CSM认证培训知识汇总
查看>>
Atitit. 。Jna技术与 解决 java.lang.Error: Invalid memory access
查看>>
zookeeper 安装和配置
查看>>
[转载] 武汉海达数云技术有限公司 - 软件研发员工资详情(武汉,2015年)
查看>>
termios编程
查看>>
html5人物图片360度立体旋转
查看>>
怎么搭建个人博客网站——我的建站过程
查看>>
SQL Server中Text和varchar(max)数据类型区别
查看>>
iOS:iOS开发系列–打造自己的“美图秀秀”(下)
查看>>
HTTP协议--cookie、session、缓存与代理
查看>>
png 2 icon
查看>>
【NLP】揭秘马尔可夫模型神秘面纱系列文章(五)
查看>>
python装饰器
查看>>
用python实现计算1-2*((60-30+(-40/5)*(9-2*5/3+7/3*99/4*2998+10*568/14))-(-4*3)/(16-3*2))类似的公式计算...
查看>>
C#中事件的继承
查看>>
Context Switch Definition
查看>>
VS2015 Git 插件使用教程
查看>>