Java并发基础--ThreadLocal
一、ThreadLocal定义
ThreadLocal是一个可以提供线程局部变量的类,ThreadLocal为解决多线程程序的并发问题提供了一种新的思路,通过为每个线程提供一个独立的变量副本解决了变量并发访问的冲突问题。在很多情况下,ThreadLocal比直接使用synchronized同步机制解决线程安全问题更简单,更方便,且结果程序拥有更高的并发性。
ThreadLocal的作用是提供线程内的局部变量,这种变量在线程的生命周期内起作用。作用:提供一个线程内公共变量(比如本次请求的用户信息),减少同一个线程内多个函数或者组件之间一些公共变量的传递的复杂度,或者为线程提供一个私有的变量副本,这样每一个线程都可以随意修改自己的变量副本,而不会对其他线程产生影响。
二、基本使用
public class ThreadLocalDemo {
public static ThreadLocal<Person> local = new ThreadLocal<Person>(){
protected Person initialValue() {
return new Person(Thread.currentThread().getName());
};
};
public static Person getPerson(){
return local.get();
}
public static void main(String[] args) {
for(int i=0;i<5;i++){
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+":"+ThreadLocalDemo.getPerson().getName());
}
}).start();
}
System.out.println(Thread.currentThread().getName()+":"+ThreadLocalDemo.getPerson().getName());
}
}
class Person{
private String name;
public Person(String name){
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
结果输出:
main:main
Thread-0:Thread-0
Thread-2:Thread-2
Thread-4:Thread-4
Thread-1:Thread-1
Thread-3:Thread-3
从结果可以看出,local对象针对不同的线程提供的Person变量是不同的。并且互不影响。同一个线程能够共享local中保存的对象。
三、源码分析
1.get()方法,用来获取当前调用get方法的线程对应在ThreadLocal中保存的变量的副本。
public T get() {
Thread t = Thread.currentThread();//获取当前线程
ThreadLocalMap map = getMap(t);//通过线程获取对应的ThreadLocalMap,ThreadLocalMap是ThreadLocal中的一个静态内部类,可将他看做一个特殊的map,key是ThreadLocal,value则是保存的变量的值。
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
}
通过线程t获取,在Thread类中定义了ThreadLocal.ThreadLocalMap threadLocals = null;即将线程和ThreadLocalMap联系起来,初始时,threadLocals=null,则需要通过setInitialValue方法创建,具体如下:
private T setInitialValue() {
T value = initialValue();//调用ThreadLocal中的initialValue方法获取变量的初始值
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);//当线程关联的ThreadLocalMap为null的时候,创建一个ThreadLocalMap,并赋值让线程t的threadLocals引用指向新创建的ThreadLocalMap对象。
return value;
}
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
通过ThreadLocal的源码分析,可以知道每个线程都有一个ThreadLocalMap类型的引用threadLocals,线程初始时候为null,当我们调用set或者get方法的时候,通过当前线程获取ThreadLocalMap,如果不为null,则通过当前threadLocal作为key,获取对应的value值。如果为null,则new ThreadLocalMap(this, firstValue);,this指向ThreadLocal对象,firstValue则是initialValue()方法中指定的初始值。
2.set()方法
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
//通过线程类Thread获取关联的ThreadLocalMap对象,如果不为null,直接调用ThreadLocalMap的set方法,设置键值对,key为ThreadLocal对象,value则为设置的值。
3.remove()方法
public void remove() {
ThreadLocalMap m = getMap(Thread.currentThread());
if (m != null)
m.remove(this);
}
四、应用场景
数据库连接,session管理,redis连接等。例如经典的使用,如下所示:
public class JdbcTemplateImpl {
// 数据库用户名
private String username;
// 数据库密码
private String password;
// 驱动信息
private String driver;
// 数据库地址
private String url;
// 声明线程共享变量
public static ThreadLocal<Connection> connections= new ThreadLocal<Connection>();
public JdbcTemplateImpl(String driver, String url, String username, String password) {
this.driver = driver;
this.url = url;
this.username = username;
this.password = password;
try {
Class.forName(this.driver);
} catch (Exception e) {
e.printStackTrace();
}
}
public Connection getConnection() {
Connection connection = connections.get();
try {
if (connection != null && !connection.isClosed()) {
return connection;
}else {
connection = DriverManager.getConnection(this.url, this.username, this.password);
connections.set(connection);
}
} catch (SQLException e) {
e.printStackTrace();
}
return connection;
}
}
Java并发基础--ThreadLocal的更多相关文章
- Java 并发基础
Java 并发基础 标签 : Java基础 线程简述 线程是进程的执行部分,用来完成一定的任务; 线程拥有自己的堆栈,程序计数器和自己的局部变量,但不拥有系统资源, 他与其他线程共享父进程的共享资源及 ...
- java并发基础及原理
java并发基础知识导图 一 java线程用法 1.1 线程使用方式 1.1.1 继承Thread类 继承Thread类的方式,无返回值,且由于java不支持多继承,继承Thread类后,无法再继 ...
- java并发基础(五)--- 线程池的使用
第8章介绍的是线程池的使用,直接进入正题. 一.线程饥饿死锁和饱和策略 1.线程饥饿死锁 在线程池中,如果任务依赖其他任务,那么可能产生死锁.举个极端的例子,在单线程的Executor中,如果一个任务 ...
- java并发基础(二)
<java并发编程实战>终于读完4-7章了,感触很深,但是有些东西还没有吃透,先把已经理解的整理一下.java并发基础(一)是对前3章的总结.这里总结一下第4.5章的东西. 一.java监 ...
- Java并发基础概念
Java并发基础概念 线程和进程 线程和进程都能实现并发,在java编程领域,线程是实现并发的主要方式 每个进程都有独立的运行环境,内存空间.进程的通信需要通过,pipline或者socket 线程共 ...
- 【搞定 Java 并发面试】面试最常问的 Java 并发基础常见面试题总结!
本文为 SnailClimb 的原创,目前已经收录自我开源的 JavaGuide 中(61.5 k Star![Java学习+面试指南] 一份涵盖大部分Java程序员所需要掌握的核心知识.欢迎 Sta ...
- java并发基础(一)
最近在看<java并发编程实战>,希望自己有毅力把它读完. 线程本身有很多优势,比如可以发挥多处理器的强大能力.建模更加简单.简化异步事件的处理.使用户界面的相应更加灵敏,但是更多的需要程 ...
- Java并发基础框架AbstractQueuedSynchronizer初探(ReentrantLock的实现分析)
AbstractQueuedSynchronizer是实现Java并发类库的一个基础框架,Java中的各种锁(RenentrantLock, ReentrantReadWriteLock)以及同步工具 ...
- Java并发基础:进程和线程之由来
转载自:http://www.cnblogs.com/dolphin0520/p/3910667.html 在前面,已经介绍了Java的基础知识,现在我们来讨论一点稍微难一点的问题:Java并发编程. ...
随机推荐
- Unity 游戏框架搭建 2018 (二) 单例的模板与最佳实践
Unity 游戏框架搭建 2018 (二) 单例的模板与最佳实践 背景 很多开发者或者有经验的老手都会建议尽量不要用单例模式,这是有原因的. 单例模式是设计模式中最简单的也是大家通常最先接触的一种设计 ...
- python统计文档中词频
python统计文档中词频的小程序 python版本2.7 效果如下: 程序如下,测试文件与完整程序在我的github中 #统计空格数与单词数 本函数只返回了空格数 需要的可以自己返回多个值 def ...
- Oracle记录类型(record)和%rowtype
Oracle中的记录类型(record)和使用%rowtype定义的数据类型都是一种单行多列的数据结构,可以理解为一个具有多个属性的对象.其中属性名即为列名. 记录类型(record) 记录类型是一种 ...
- Redis的数据类型以及各类型的操作
讲完安装和配置,接下来就是所有数据库的重头戏,数据结构和常用操作的增删改查了 redis是key-value的数据结构,每条数据都是⼀个键值对 键的类型是字符串 注意:键不能重复 值的类型分为五种: ...
- excel批量转换为CSV格式,xls批量导出csv格式
工具/原料 excel 2013 地址链接:http://pan.baidu.com/s/1c1ZABlu 密码:d3rc 方法/步骤 首选我们把需要导出为CVS的Excel文件整理集中到 ...
- Django学习笔记3-静态文件调用
1.settings.py 静态文件相关示例代码及说明: # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.c ...
- python字符编码转换说明及深浅copy介绍
编码说明: 常用编码介绍: ascii 数字,字母 特殊字符. 字节:8位表示一个字节. 字符:是你看到的内容的最小组成单位. abc : a 一个字符. 中国:中 一个字符. a : 0000 10 ...
- Python 简单购物车
product_list =[ ('huawei',3000), ('hongmiNote3',3000), ('sanxing',2600), ('ThinkPad870',15000), ('Ip ...
- 自己写的代码实现Session
package com.zq.web.context.windows; import java.util.HashMap;import java.util.Map; import org.apache ...
- vue中将html字符串转换成html后的一些问题
今天整理之前做vue项目时遇到的一些问题,发现了当时遇到的一个很小但是又会引出很多问题的一个问题(总之就是很有意思,听我慢慢给你到来),这个问题就是当时处理后端数据时,如何将后端返回来的字符串转换成h ...