ThreadLocal讲解
一、前言
ThreadLocal这个对象就是为多线程而生的,没有了多线程ThreadLocal就没有存在的必要了。可以将任何你想在每个线程独享的对象放置其中,并在任何时候取出来。
二、基本用法
ThreadLocal的使用方法其实特别简单:
- 在某个类(相当于工厂类,因为当获取不到的时候你要创建一个给它)中创建静态的ThreadLocal。
- 在别的地方调用它的set和get方法用来存放对象。
下面展示一个样例:

package yiwangzhibujian;
public class ThreadLocalUse{
//创建一个静态的ThreadLocal对象,当做仓库,存储每个线程自己的资源
//此处用Object来代替,可以使连接Connection
private static ThreadLocal<Object> store=new ThreadLocal<Object>();
//当每个线程要获取一个线程资源的时候,调用get方法
public Object get(){
//首先去仓库中去寻找
Object obj=store.get();
//如果不存在那就创建一个给线程,并把创建的放到仓库中
if(obj==null){
obj=new Object();
set(obj);
}
return obj;
}
//想将线程资源放到仓库调用set方法,
public void set(Object obj){
store.set(obj);
}
}

这是一个使用模板,可以根据具体情况来做相应改变。
三、ThreadLocal理解
3.1 ThreadLocal会导致内存泄漏吗
首先明确表示使用ThreadLocal不会导致内存泄漏。现在做如下测试证明这个观点,有如下程序:

public class ThreadLocalTest{
//创建一个ThreadLocal用来存储每个线程的对象
private static ThreadLocal<Object> local=new ThreadLocal<Object>();
//一个常量,用来创建10M大小的对象使用
private static final int _1MB=1024*1024;
public static void main(String[] args) throws Exception{
//创建一个Runnable对象
Runnable r=new Runnable(){
@Override
public void run(){
System.out.println("子线程内创建对象并放置ThreadLocal中");
//创建一个10M大小的数组,并将其放到ThreadLocal中
byte[] data=new byte[10*_1MB];
local.set(data);
System.out.println("子线程运行结束,代表线程结束");
}
};
//创建线程并运行
Thread t=new Thread(r);
t.start();
System.out.println("主线程休眠一秒,为了让创建的子线程执行完毕");
Thread.sleep(1000);
System.out.println("休眠完成,主线程准备分配一个10M大小的数组");
byte[] data2=new byte[10*_1MB];
System.out.println("分配数组完毕");
}
}

在程序右键点击Run as->Run Configurations进行虚拟机配置:

配置如下,-XX:+PrintGCDetails(打印垃圾回收日志) -XX:+PrintGCTimeStamps(打印回收时间,可不用) -Xms18M -Xmx18M(设置初始化和最大内存为18M,这么做的目的是,当创建两个10M大小的数组时,会内存溢出还是将ThreadLocal内的进行回收):

首先介绍这个程序的目的就是创建一个对象放置到ThreadLocal中,看看垃圾回收器会不会在线程结束的时候对其进行回收。运行结果如下:

主线程休眠一秒,为了让创建的子线程执行完毕
子线程内创建对象并放置ThreadLocal中
子线程运行结束,代表线程结束
休眠完成,主线程准备分配一个10M大小的数组
1.102: [GC [PSYoungGen: 376K->224K(5376K)] 10616K->10464K(17664K), 0.0077785 secs] [Times: user=0.03 sys=0.00, real=0.01 secs]
1.110: [GC [PSYoungGen: 224K->224K(5376K)] 10464K->10464K(17664K), 0.0008971 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
1.111: [Full GC [PSYoungGen: 224K->0K(5376K)] [PSOldGen: 10240K->164K(12288K)] 10464K->164K(17664K) [PSPermGen: 3030K->3030K(21248K)], 0.0058052 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
分配数组完毕

可以发现,当主线程准备分配一个10M大小的数组时发现内存不够,会调用垃圾处理器进行回收,通过[PSOldGen: 10240K->164K(12288K)] 可以看出,放入ThreadLocal中的对象被回收了。
3.2 使用全局Map替换ThreadLocal可不可以
我曾经也想过使用全局Map来替换ThreadLocal,即使用如下代码表示展示的样例:

public class ThreadLocalUse{
private static Map<Thread,Object> store=new HashMap<Thread,Object>();
//当每个线程要获取一个线程资源的时候,调用get方法
public Object get(){
//首先去仓库中去寻找
Object obj=store.get(Thread.currentThread());
//如果不存在那就创建一个给线程,并把创建的放到仓库中
if(obj==null){
obj=new Object();
set(obj);
}
return obj;
}
//想将线程资源放到仓库调用set方法,
public void set(Object obj){
store.put(Thread.currentThread(),obj);
}
}

这样也可以做到线程内共享对象,但是有一个致命的缺点,那就是当线程结束后,存储在Map中的对象必须手动清除,否则将会导致内存泄漏。
3.3 对比ThreadLocal和synchronized同步机制
很多人都会对这两个对象进行比对,我也谈一下我自己的想法。
使用synchronized是为了将多条语句进行原子化操作,比说对于递增操作i++,任意一个线程在执行代码时都要保证别的线程不能执行这个代码,否则就会产生脏数据,使用synchronized可以避免这一点。
而使用ThreadLocal就是给每个线程存储对象用的。既然每个线程使用了自己的对象,没有了竞争就不会出现多线程相关的问题。
3.4 我对ThreadLocal的一点点理解
本来呢,我也一直在想ThreadLocal设计的有一点点不合理,比如为什么只能存储一个对象呢,存储多个对象多好呀,或者Thread直接内置一个Map多好,就可以这样操作:
Thread.currentThread().map.put(key,value);
Thread.currentThread().map.get(key);
ThreadLocal讲解的更多相关文章
- 赌十包辣条,你一定没见过这么通透的ThreadLocal讲解
1.看个热闹 鉴于普罗大众都喜欢看热闹,咱们先来看个热闹再开工吧! 场景一: 中午了, 张三.李四和王五一起去食堂大菜吃饭.食堂刚经营不久,还很简陋,负责打菜的只有一位老阿姨. 张三:我要一份鸡腿. ...
- 我是如何理解ThreadLocal
ThreadLocal的概念 ThreadLocal从英文的角度看,可以看成thread和local的组合,就是线程本地的意思,我们都知道,看过jvm内存分配的人都知道在jvm虚拟机中对每一个线程都分 ...
- java面试总结
一.java的集合框架 HashMap.HashTable.CurrentHashMap的底层数据结构与区别? CurrentHashMap与HashTable是如何保证线程安全的? ArrayLis ...
- ThreadLocal实现方式&使用介绍—无锁化线程封闭
原文出处: xieyu_zy 虽然现在可以说很多程序员会用ThreadLocal,但是我相信大多数程序员还不知道ThreadLocal,而使用ThreadLocal的程序员大多只是知道其然而不知其所以 ...
- Java多线程9:ThreadLocal源码剖析
ThreadLocal源码剖析 ThreadLocal其实比较简单,因为类里就三个public方法:set(T value).get().remove().先剖析源码清楚地知道ThreadLocal是 ...
- ThreadLocal实现方式&使用介绍---无锁化线程封闭
虽然现在可以说很多程序员会用ThreadLocal,但是我相信大多数程序员还不知道ThreadLocal,而使用ThreadLocal的程序员大多只是知道其然而不知其所以然,因此,使用ThreadLo ...
- Java中ThreadLocal无锁化线程封闭实现原理
虽然现在可以说很多程序员会用ThreadLocal,但是我相信大多数程序员还不知道ThreadLocal,而使用ThreadLocal的程序员大多只是知道其然而不知其所以然,因此,使用ThreadLo ...
- 事务管理在三层架构中应用以及使用ThreadLocal再次重构
本篇将详细讲解如何正确地在实际开发中编写事务处理操作,以及在事务处理的过程中使用ThreadLocal的方法. 在前面两篇博客中已经详细地介绍和学习了DbUtils这个Apache的工具类,那么在本篇 ...
- 【Java并发系列03】ThreadLocal详解
img { border: solid 1px } 一.前言 ThreadLocal这个对象就是为多线程而生的,没有了多线程ThreadLocal就没有存在的必要了.可以将任何你想在每个线程独享的对象 ...
随机推荐
- 小波变化库——Pywalvets学习笔记
笔记 术语(中英对照): 尺度函数:scaling function(又称父函数 father wavelet) 小波函数:wavelet function(又称母函数 mother wavelet) ...
- JavaScript权威指南--事件处理
知识要点 客户端JavaScript程序采用了异步事件驱动变成模型(13.3.2节).这种风格并不只应用于web编程,所有使用图形用户界面的应用程序都采用它,它们静待某些事件发生,然后响应. 事件就是 ...
- Shell需注意的语法问题
1.文件头声明别漏掉#和! #!/bin/bash 2.赋值语句①=号两端不能有空格(判断语句=号两端必须有空格)②使用变量必须使用符号$ var1=valecho $var1 3.if语句写错下面任 ...
- Python mysql-表的创建,删除和更新
2017-09-06 20:59:56 数据库的创建 CREATE DATEBASE <数据库的名称> 表的创建 CREATE TABLE <表名> (<列名1> ...
- Windows下openssl的下载安装和使用
Windows下openssl的下载安装和使用 安装openssl有两种方式,第一种直接下载安装包,装上就可运行:第二种可以自己下载源码,自己编译.下面对两种方式均进行详细描述. 一.下载和安装ope ...
- JDK1.7 新特性
1:switch中可以使用字串 String s = "test"; switch (s) { case "test" : System. ...
- 3-19(晚) require_relative 和 require. === operator的解释。
kernel#require_relative Ruby tries to load the library named string relative to the requiring file's ...
- devilbox(二):连接数据库
Devilbox的安装在上一篇https://www.cnblogs.com/ermao0423/p/9505653.html中已经记录了,这篇主要记录各种数据库的连接.用户建立.设置密码等 查看do ...
- Java compiler level does not match the version of the installed Java project facet.解决方法
右键项目“Properties”,在弹出的“Properties”窗口左侧,单击“Project Facets”,打开“Project Facets”页面. 在页面中的“Java”下拉列表中,选择相应 ...
- dp练习(1)——马走日字
3328: 马走日字 时间限制: 1 Sec 内存限制: 128 MB提交: 35 解决: 5[提交][状态][讨论版] 题目描述 一次外出旅游,你路上遇到了一个骑着马的强盗,你很害怕,你需要找一 ...