转载请标明出处:

http://blog.csdn.net/forezp/article/details/77620769

本文出自方志朋的博客

什么是线程封闭

当访问共享变量时,往往需要加锁来保证数据同步。一种避免使用同步的方式就是不共享数据。如果仅在单线程中访问数据,就不需要同步了。这种技术称为线程封闭。在Java语言中,提供了一些类库和机制来维护线程的封闭性,例如局部变量和ThreadLocal类,本文主要深入讲解如何使用ThreadLocal类来保证线程封闭。

理解ThreadLocal类

ThreadLocal类能使线程中的某个值与保存值的对象关联起来,它提供了get、set方法,这些方法为每个使用该变量的线程保存一份独立的副本,因此get总是set当前线程的set最新值。

首先我们来看个例子,这个例子来自于http://www.cnblogs.com/dolphin0520/p/3920407.html


public class Test1 { ThreadLocal<Long> longLocal = new ThreadLocal<Long>();
ThreadLocal<String> stringLocal = new ThreadLocal<String>(); public void set() {
longLocal.set(Thread.currentThread().getId());
stringLocal.set(Thread.currentThread().getName());
} public long getLong() {
return longLocal.get();
} public String getString() {
return stringLocal.get();
}
public static void main(String[] args) throws InterruptedException {
final Test1 test = new Test1(); test.set();
System.out.println(test.getLong());
System.out.println(test.getString()); Thread thread1 = new Thread(() -> {
test.set();
System.out.println(test.getLong());
System.out.println(test.getString());
});
thread1.start();
thread1.join(); System.out.println(test.getLong());
System.out.println(test.getString());
}
}

运行该程序,代码输出的结果为:

1

main

10

Thread-0

1

main

从这段代码可以看出在mian线程和thread1线程确实都保存着各自的副本,它们的副本各自不干扰。

ThreadLocal源码解析

来从源码的角度来解析ThreadLocal这个类,这个类存放在java.lang包,这个类有很多方法。

它内部又个ThreadLocalMap类,主要有set()、get()、setInitialValue 等方法。

首先来看下set方法,获取当前Thread的 map,如果不存在则新建一个并设置值,如果存在设置值,源码如下:

public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}

跟踪createMap,可以发现它根据Thread创建来一个ThreadLocalMap。

  void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue);
}

t.threadLocals为当前线程的一个变量,也就是ThreadLocal的数据都是存放在当前线程的threadLocals变量里面的,由此可见用ThreadLocal存放的数据是线程安全的。因为它对于不同的线程来,使用ThreadLocal的set方法都会根据线程判断该线程是否存在它的threadLocals成员变量,如果没有就建一个,有的话就存下数据。

ThreadLocal.ThreadLocalMap threadLocals = null;

ThreadLocalMap为ThreadLocal的一个内部类,源码如下:

 static class ThreadLocalMap {

        static class Entry extends WeakReference<ThreadLocal<?>> {
/** The value associated with this ThreadLocal. */
Object value; Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}

可以看到ThreadLocalMap的Entry继承了WeakReference,并且使用ThreadLocal作为键值。

在使用ThreadLocal的get方法之前一定要先set,要不然会报空指针异常。还有一种方式就是在初始化的时候调用initialValue()方法赋值。改造下之前的例子,代码如下:

public class Test2 {

    ThreadLocal<Long> longLocal = new ThreadLocal<Long>(){

        @Override
protected Long initialValue() {
return Thread.currentThread().getId();
}
};
ThreadLocal<String> stringLocal = new ThreadLocal<String>(){
@Override
protected String initialValue() {
return Thread.currentThread().getName();
}
}; public long getLong() {
return longLocal.get();
} public String getString() {
return stringLocal.get();
} public static void main(String[] args) throws InterruptedException {
final Test2 test = new Test2(); System.out.println(test.getLong());
System.out.println(test.getString()); Thread thread1 = new Thread(() -> { System.out.println(test.getLong());
System.out.println(test.getString());
});
thread1.start();
thread1.join(); System.out.println(test.getLong());
System.out.println(test.getString());
}
}

运行该程序,代码输出的结果为:

1

main

10

Thread-0

1

main

ThreadLocal常用的使用场景

通常讲JDBC连接保存在ThreadLocal对象中,每个对象都有属于自己的连接,代码如下:

private static ThreadLocal<Connection> connectionHolder
= new ThreadLocal<Connection>() {
public Connection initialValue() {
return DriverManager.getConnection(DB_URL);
}
}; public static Connection getConnection() {
return connectionHolder.get();
}

参考资料

《Java并发编程实战》

《深入理解JVM》




扫码关注公众号有惊喜

(转载本站文章请注明作者和出处 方志朋的博客

Java并发编程:线程封闭和ThreadLocal详解的更多相关文章

  1. Java并发编程--线程封闭(Ad-hoc封闭 栈封闭 ThreadLocal)

    线程封闭实现好的并发是一件困难的事情,所以很多时候我们都想躲避并发.避免并发最简单的方法就是线程封闭.什么是线程封闭呢?就是把对象封装到一个线程里,只有这一个线程能看到此对象.那么这个对象就算不是线程 ...

  2. java并发编程(七)synchronized详解

    Java语言的关键字,当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码.     一.当两个并发线程访问同一个对象object中的这个synchronized( ...

  3. Java 并发编程(一) → LockSupport 详解

    开心一刻 今天突然收到花呗推送的消息,说下个月 9 号需要还款多少钱 我就纳了闷了,我很长时间没用花呗了,怎么会欠花呗钱? 后面我一想,儿子这几天玩了我手机,是不是他偷摸用了我的花呗 于是我找到儿子问 ...

  4. Java 并发编程 | 线程池详解

    原文: https://chenmingyu.top/concurrent-threadpool/ 线程池 线程池用来处理异步任务或者并发执行的任务 优点: 重复利用已创建的线程,减少创建和销毁线程造 ...

  5. Java并发编程:深入剖析ThreadLocal (总结)

    ThreadLocal好处 Java并发编程的艺术解释好处是:get和set方法的调用可以不用在同一个方法或者同一个类中. 问答形式总结: 1. ThreadLocal类的作用 ThreadLocal ...

  6. Java并发编程:深入剖析ThreadLocal(转载)

    Java并发编程:深入剖析ThreadLocal(转载) 原文链接:Java并发编程:深入剖析ThreadLocal 想必很多朋友对ThreadLocal并不陌生,今天我们就来一起探讨下ThreadL ...

  7. (转)Java并发编程:深入剖析ThreadLocal

    Java并发编程:深入剖析ThreadLoca Java并发编程:深入剖析ThreadLocal 说下自己的理解:使用ThreadLocal能够实现空间换时间,重在理解ThreadLocal是如何复制 ...

  8. 【转载】 Java并发编程:深入剖析ThreadLocal

    原文链接:http://www.cnblogs.com/dolphin0520/p/3920407.html感谢作者的辛苦总结! Java并发编程:深入剖析ThreadLocal 想必很多朋友对Thr ...

  9. 7、Java并发编程:深入剖析ThreadLocal

    Java并发编程:深入剖析ThreadLocal 想必很多朋友对ThreadLocal并不陌生,今天我们就来一起探讨下ThreadLocal的使用方法和实现原理.首先,本文先谈一下对ThreadLoc ...

随机推荐

  1. HDU 1394——Minimum Inversion Number——————【线段树单点增减、区间求和】

    Minimum Inversion Number Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & ...

  2. 文件读取工具类读取properties文件

    1.创建工具类 import java.io.IOException; import java.util.Properties; /** * * 类名称:PropertiesUtil * 类描述: 文 ...

  3. java版两人聊天程序

    server.java import java.io.*; import java.net.*; import java.text.SimpleDateFormat; import java.util ...

  4. Android的Overlay机制

    相关知识点的掌握: AAPT的使用和原理 编译脚本 参考:http://blog.sina.com.cn/s/blog_645b74b90101ojkc.html

  5. HDU 4731 找规律,打表

    http://acm.hust.edu.cn/vjudge/contest/126262#problem/D 分为3种情况,n=1,n=2,n>=3 其中需要注意的是n=2的情况,通过打表找规律 ...

  6. 重构指南 - 使用多态代替条件判断(Replace conditional with Polymorphism)

    多态(polymorphism)是面向对象的重要特性,简单可理解为:一个接口,多种实现. 当你的代码中存在通过不同的类型执行不同的操作,包含大量if else或者switch语句时,就可以考虑进行重构 ...

  7. Vector 、ArrayList、LinkedList比较

    这三者都可以随机访问,也就是支持通过索引查找数据. 都是有序(可以实现元素怎么进怎么出) Vector和ArrayList比较 相同之处 1 它们都是List 它们都继承于AbstractList,并 ...

  8. python dict list tuple

    Dict 创建 somedict = {} somedict = {"key": value} a = dict(one=1, two=2, three=3) c = dict(z ...

  9. 从零开始的全栈工程师——html篇1.3

    文本.字体css样式与前期英语单词汇总 一.文本样式(text) 1.颜色:color:red; 2.文本对齐方式:text-align:left/center/right/justify; left ...

  10. mysql四-2:多表查询

    一.介绍 本节主题: 多表连接查询 复合条件连接查询 子查询 准备表: #建表 create table department( id int, name ) ); create table empl ...