-
ThreadLocal
回到顶部
ThreadLocal 与 Thread 同步机制的比较
- Thread同步机制采用了以时间换空间方式,通过对象锁保证在同一个时间,对于同一个实例对象,只有一个线程访问。
- ThreadLocal 采用以空间换时间方式,为每一个线程都提供一份变量,各线程间同时访问互不影响。
回到顶部
定义ThreadLocal的同时为当前线程的局部变量副本赋初始值
✅ 方式1:ThreadLocal#withInitial(Supplier<? extends S> supplier)
withInitial的参数是函数式接口Supplier<T> ,通过调用其get方法得到结果(Supplier<T>, in/since jdk1.8, a functional interface whose functional method is {@link #get()},represents a supplier of results.)。
private static ThreadLocal<StringBuilder> threadLocal = ThreadLocal.withInitial(StringBuilder::new);
✅ 方式2:覆写protected方法initialValue():
private static ThreadLocal<StringBuilder> threadLocal = new ThreadLocal<StringBuilder>() { @Override protected StringBuilder initialValue() { return new StringBuilder(); } };
回到顶部
ThreadLocal无法解决共享对象的更新问题
对于如下代码。 threadLocal里操作的StringBuilder与全局StringBuilder是同一个内存对象。 所以,在多线程往自己的ThreadLocal里的StringBuilder里append数据的时候,操作的都是全局的StringBuilder。 所以,这段代码定义的ThreadLocal<StringBuilder>没有任何意义。 因为StringBuilder是线程不安全的,所以,会出现线程不安全问题:某些并发场景下会出现有的线程没有append进去。 如果想实现线程安全,那么,不是用ThreadLocal,而是用线程安全的StringBuffer,或者借助线程同步锁。
static StringBuilder sb = new StringBuilder("init"); private static ThreadLocal<StringBuilder> threadLocal = ThreadLocal.withInitial(() -> sb);
所以说,最好不要用ThreadLocal来操作共享对象。 尽量仅让其持有当前线程里的对象。
完整示例代码 of ThreadLocal无法解决共享对象的更新问题
package jstudy.threadlocal; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.RandomUtils; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; /** * {@link java.lang.ThreadLocal}无法解决共享对象的更新问题。本代码实例将证明这一点。 * 结果虽然都append了,但是,是无序的 * 所以,使用某个引用来操作共享对象时,依然需要进行线程同步 */ @Slf4j public class InitValueInThreadLocal { static StringBuilder sb = new StringBuilder("init"); private static ThreadLocal<StringBuilder> threadLocal = ThreadLocal.withInitial(StringBuilder::new); static AtomicInteger integer = new AtomicInteger(); public void print() { StringBuilder stringBuilder = threadLocal.get(); int j = integer.getAndIncrement(); log.info("初始:{} val={}", stringBuilder.toString(), j); try { Thread.sleep(RandomUtils.nextInt(0, 5)); } catch (InterruptedException e) { e.printStackTrace(); } stringBuilder.append("-" + j); threadLocal.remove(); log.info(stringBuilder.toString()); } public static void main(String[] args) throws InterruptedException { for (int i = 0; i < 5; i++) { InitValueInThreadLocal1 ins = new InitValueInThreadLocal1(); new Thread(() -> ins.print()).start(); } TimeUnit.SECONDS.sleep(2); log.info(sb.toString()); } }
由于StringBuilder线程不安全,如下是 意料之外的结果。main方法里启动了5个线程,所以,本应该把0、1、2、3、4这5个数字append到sb对象里,却发现0没有append进去。
来源:https://www.cnblogs.com/buguge/p/15824081.html
栏目列表
最新更新
Python采集ip代理,并检测是否可用(仅用
用python实现微信、钉钉等软件多开
利用Python解决掉谷歌人机验证,全自动识
用python写一个自动生成春联的软件,打包
Python写的一个GUI界面的小说爬虫软件
用python爬取jk小姐姐照片慢慢看「本地直
超方便的 Python 自动唤醒窗口截图脚本
5个方便好用的Python自动化脚本
刚刚出炉的冬奥会吉祥物:冰墩墩,附源
没买抢冰墩墩,那咱们自己用python画一个
SQL分库分表
关于如何在window下执行SQLSERVER的定时备份
SQLServer高可用方案在企业生产环境的实践
SQL Server HA - 高可用性解决方案解决方案概
独家揭秘:SQL Server AlwaysOn在阿里云的突破
sqlserver数据库还原存储过程脚本
MongoDB常用命令(2)
MongoDB基本介绍与安装(1)
SQLServer触发器调用JavaWeb接口
SQL Server索引的原理深入解析
Ubuntu 16.04 更改系统语言为简体中文 ####
【JavaScript】笔记(7)--- JSON(对象的创建
大前端工程化之写一个简单的webpack插件
前端基础之JavaScript(二)
前端基础之JavaScript(一)
大前端JS篇之搞懂【WeakSet】
增删商品计算价格
【JavaScript】笔记(6)--- BOM(open 与 clo
【JavaScript】笔记(5)--- DOM(续)(复选
【JavaScript】笔记(4)--- DOM(初步)(获取文