ThreadLocal 与 static 变量
参考文章:ThreadLocal 与static变量
ThreadLocal是为解决多线程程序的并发问题而提出的,可以称之为线程局部变量。与一般的变量的区别在于,生命周期是在线程范围内的。
static变量是的生命周期与类的使用周期相同,即只要类存在,那么static变量也就存在。
那么一个 static 的 ThreadLocal会是什么样的呢?
看下面一个例子,
public class SequenceNumber { private static ThreadLocal<Integer> seqNum = new ThreadLocal<Integer>(){ public Integer initialValue(){ return 0; } }; public int getNextNum() { seqNum.set(seqNum.get() + 1); return seqNum.get(); } public static void main(String[] args) { SequenceNumber sn = new SequenceNumber(); TestClient t1 = new TestClient(sn); TestClient t2 = new TestClient(sn); TestClient t3 = new TestClient(sn); t1.start(); t2.start(); t3.start(); t1.print(); t2.print(); t3.print(); } private static class TestClient extends Thread { private SequenceNumber sn; public TestClient(SequenceNumber sn ) { this.sn = sn; } public void run() { for(int i=0; i< 3; i++) { System.out.println( Thread.currentThread().getName() + " --> " + sn.getNextNum()); } } public void print() { for(int i=0; i< 3; i++) { System.out.println( Thread.currentThread().getName() + " --> " + sn.getNextNum()); } } }
}
下面是结果
Thread-2 --> 1
Thread-2 --> 2
Thread-2 --> 3
Thread-0 --> 1
Thread-0 --> 2
Thread-0 --> 3
Thread-1 --> 1
Thread-1 --> 2
Thread-1 --> 3
main --> 1
main --> 2
main --> 3
main --> 4
main --> 5
main --> 6
main --> 7
main --> 8
main --> 9
可以发现,static的ThreadLocal变量是一个与线程相关的静态变量,即一个线程内,static变量是被各个实例共同引用的,但是不同线程内,static变量是隔开的。
下面的实例能够体现Spring对有状态Bean的改造思路:
代码清单3 TopicDao:
// 非线程安全
public class TopicDao {// 一个非线程安全的变量private Connection conn;public void addTopic() {// 引用非线程安全变量Statement stat = conn.createStatement(); …}
}
由于1处的conn是成员变量,因为addTopic()方法是非线程安全的,必须在使用时创建一个新TopicDao实例(非singleton)。
下面使用ThreadLocal对conn这个非线程安全的“状态”进行改造:
代码清单4 TopicDao:
// 线程安全
package threadLocalDemo;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;public class SqlConnection {// 1. 使用ThreadLocal保存Connection变量privatestatic ThreadLocal<Connection> connThreadLocal = new ThreadLocal<Connection>();publicstatic Connection getConnection() {// 2. 如果connThreadLocal没有本线程对应的Connection创建一个新的Connection,// 并将其保存到线程本地变量中。if (connThreadLocal.get() == null) {Connection conn = getConnection();connThreadLocal.set(conn);return conn;} else {return connThreadLocal.get();// 3. 直接返回线程本地变量}}public voidaddTopic() {// 4. 从ThreadLocal中获取线程对应的Connectiontry {Statement stat = getConnection().createStatement();} catch (SQLException e) {e.printStackTrace();}}
}
为何通常将ThreadLocal变量设置为static
理由:
为了避免重复创建TSO(thread specific object,即与线程相关的变量)。
需要注意的是:无法解决共享对象的更新问题。(引用于《阿里巴巴JAVA开发规范》)
static定义的类变量本来是可以进行变量共享的,但是因为ThreadLocal根除了对变量的共享,所以static Thread< xxx> object无法实现类的共享和同步更新。
分析
一个ThreadLocal实例对应当前线程中的一个TSO实例。因此,如果把ThreadLocal声明为某个类的实例变量(而不是静态变量),那么每创建一个该类的实例就会导致一个新的TSO实例被创建。显然,这些被创建的TSO实例是同一个类的实例。于是,同一个线程可能会访问到同一个TSO(指类)的不同实例,这即便不会导致错误,也会导致浪费(重复创建等同的对象)!因此,一般我们将ThreadLocal使用static修饰即可。
由于ThreadLocal是某个类的一个静态变量。因此,只要相应的类没有被垃圾回收掉,那么这个类就会持有对相应ThreadLocal实例的引用。
什么是ThreadLocal?
java.lang.ThreadLocal类实现了线程的本地存储,我们可以用该类来创建和管理线程。
ThreadLocal的内部实现:
ThreadLocal的内部实现包括一个类似HashMap的对象,这里称之为ThreadLocalMap。
ThreadLocalMap的key会持有对ThreadLocal实例的弱引用(Weak Reference),value会引用TSO实例。
具体的可以参考:彻底理解ThreadLocal
ThreadLocal的使用:
《thinking in java 第四版》p690
ThreadLocal 与 static 变量相关推荐
- 为什么jdk源码推荐ThreadLocal使用static
ThreadLocal是线程私有变量,本身是解决多线程环境线程安全,可以说单线程实际上没必要使用. 既然多线程环境本身不使用static,那么又怎么会线程不安全.所以这个问题本身并不是问题,只是有人没 ...
- 【Android 异步操作】手写 Handler ( Message 消息 | ThreadLocal 线程本地变量 | Looper 中的消息队列 MessageQueue )
文章目录 一.Message 消息 二.ThreadLocal 线程本地变量 三.Looper 中的消息队列 MessageQueue 一.Message 消息 模仿 Android 中的 Messa ...
- Java static变量保存在哪?
测试环境: Microsoft Windows [版本 10.0.17134.165] java -version java version "1.8.0_171" Java(TM ...
- 局部变量和static变量
局部变量:指在程序中,只在特定过程或函数中可以访问的变量,是相对于全局变量而言的.在C++.C#.Ruby这些面向对象语言中,一般只使用局部变量.在面向对象编程中现在普遍采用的是软件开发方法,因此无需 ...
- 一种安全的static变量Get/Set方式
目的:避免static变量是个文件内可见的全局变量 Get: std::atomic<bool>* GetGraphVerboseStepLr() {static std::atomic& ...
- (转)static 变量
一. static 变量 static变量大致分为三种用法 1. 用于局部变量中,成为静态局部变量. 静态局部变量有两个用法,记忆功能和全局生存期. 2. 用于全局变量,主要作用是限制此全局变量被其他 ...
- springboot下Static变量通过@Value和set方法注入失败的问题和解决办法
首先static变量是不能直接使用@value进行注入. 但是也不是没有办法.操作如下: 1.在这个变量的类上标上注解@Component 2.通过set方法就可以,给在set方法上使用@Value注 ...
- java static变量销毁_JAVA里static 变量在程序执行结束后是否被消毁
static变量是属于类的,一般情况下,程序执行结束后,类所占空间会被回收, static变量自然就被销毁了. 如下所示: public class StaticVar{ public static ...
- 关于static变量,请选择下面所有说法正确的内容
若全局变量仅在单个C文件中访问,则可以将这个变量修改为静态全局变量,以降低模块间的耦合度 若全局变量仅由单个函数访问,则可以将这个变量改为该函数的静态局部变量,以降低模块间的耦合度 设计和使用访问动态 ...
最新文章
- mysql 5.7 收费_MySQL5.7 常用用户操作
- Java平均工资再次上涨!这份宝藏资料限量免费送!
- 致青春VS杜蕾斯,用QQ空间电影大数据解读关联性
- 自学Zabbix3.0版本以上资产清单inventory
- mysql 分表 sphinx_sphinx(coreseek)处理分表的方案
- 数据结构实验之栈六:下一较大值(二)
- host文件注释 ubuntu_Redis and MongoDB 设置密码验证(scrapy)(win)(ubuntu)
- linux rmp命令安装包在哪里_一文带你了解阿里云Linux服务器的基本操作
- Regularized logistic regression(正则化逻辑回归)----吴恩达机器学习
- 携程python面试题_Python求解啤酒问题(携程2016笔试题)
- Python--所有的库
- SZTUOJ 1008.盒子游戏
- 【教育小程序案例】线下培训机构辅导教育
- JAVA-DS-排序
- 多线程(一) 线程概念及创建线程的方法
- C++学习之分式化简
- ESP-01S开发环境搭建及新手教程点灯教程全解详细配图(ESP8266-01s)
- Windows 7防火墙设置详解(一)
- 2020.6最新清晰的图教学!!(25行代码破解酷我音乐所有歌曲)
- 游戏制作RPGDreamer
热门文章
- 【濡白的C语言】初学者-从零开始-2(常量,一维数组,转义字符)
- lastIndexOf()使用方法
- 中e管家快速学会投资理财
- 副主任护师计算机考试试题,副主任护师考试科目
- 奉劝那些想做客户端开发学弟学妹们!呕心沥血,真情实感,字字诛心
- “参与感”营销策略,其实就是“宠粉”战役
- ETL工具(kettle) 与 ETL产品(BeeloadBeeDI) 差之毫厘,谬以千里
- 设置了JOB,但是 不执行
- Python 一元二次方程
- 详解setTimeout()