java 线程安全解决方案-android 线程阻塞怎么解决
码农的世界,从来不缺名词。 如果没有,我们会强制一些。 这些名词有垂直领域的知识缩写和水平领域的抽象划分。 有的顺畅顺畅,有的像便秘一样晦涩难懂。
在java并发编程中,有一个比较晦涩的名词叫线程闭包。 在之前的技术交流中,经常会提到这个东西。 那么它的神圣之处在哪里,它有什么用处呢?
如果你在网上搜索文章,你会得到三个选项。
1)临时线程关闭。
2)堆栈关闭。
3) ThreadLocal 类。
这些知识是隔着一层窗户纸戳破的,内容其实并不复杂。 这些名词太可怕了,要记住它们真是太麻烦了。
意义?
我们都知道,如果一个变量被多个线程使用,必然会引入同步问题。 除了synchronization关键字,Java还引入了多种技术来实现多线程同步,包括wait、notify、reentrant Lock、AQS等,这种编程方式会增加程序的复杂度,使得代码容易出现bug。
如果有一些数据只和线程相关,对线程外的数据不可见,那么代码会好写很多。 实现这种效果的技术统称为线程禁闭。
这是前提。 接下来我们看看实现。
堆栈关闭
栈闭包属于强制集合概念的范畴。 写代码的人其实是看不到的。 它是 JVM 中虚拟机堆栈或本地方法堆栈的默认行为。 其实这个结果我们早就知道了:成员变量是线程共享的,而局部变量是线程相关的。
很简单,但是背后的原理需要对JVM有深刻的理解。 为了理解这个功能,我们需要对JVM的内存区域划分有一个初步的了解。
除了存储空间最大的堆java 线程安全解决方案,JVM还有线程相关的、运行的栈。 栈闭包是指与线程相关的栈的相关行为。
我们稍微回忆一下上图中的内存划分。 栈闭包指的是图中彩色部分与线程相关的内存区域。
我们还可以再深入一点。
虚拟机栈上的基础数据其实就是一个叫做栈帧的东西。 您可以将堆栈帧视为方法的执行。
每个方法入栈后,都有局部变量表、操作数栈、动态链接、返回地址等信息。 我们的局部变量其实就存在于这些地方。 因为他们的祖先最终只会指向一个线程,所以他们的作用域是封闭的。
如上图所示,局部变量与一个线程的关系。 java中也有线程执行的内存模型JMM,不过那是变量的复制和同步,不是一回事。
线程局部
事实上,java提供给开发者的线程闭包API只有ThreadLocal。
在Thread类中,有一个成员变量threadLocals,里面存放了所有与这个线程相关的自定义信息。 这个变量的定义在Thread中,但是操作在ThreadLocal类中。
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
...
}
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
ThreadLocal的用法有很多,比如常用的,每个线程都会生成一个线程不安全的SimpleDateFormat。
ThreadLocal sdf = new ThreadLocal();
sdf.set(new SimpleDateFormat());
关于ThreadLocal无需过多介绍,查下jdk源码,红利尽收眼底。
特别指定
这些资料大部分来自《JAVA并发编程》一书。 我特意搜索了一下Ad-hoc这个名字的意思。
Ad-hoc模式与之前的直接双绞线概念相同,是P2P连接,因此无法与其他网络中的节点通信,减少干扰。
在英语中作为形容词,有“特殊”、“暂时”之意。
实在想不明白为什么要用这样的命名。
该方法完全由实现者控制,因此非常脆弱。
嗯,看来还是老老实实用ThreadLocal比较好。
结尾
我们来看看这三个方法的去向。 其中之一是JVM内部实现,原理知识; Ad-hoc告诉用户这种线程关闭难度很大,赶紧放弃; 最后,我们手中只有ThreadLocal。
我似乎看到ThreadLocal在向胜利招手java 线程安全解决方案,同时我的名词字典里多了几个:线程闭包,栈闭包,Ad-hoc。
作者简介:小姐姐品味(xjjdog),一个不允许程序员走弯路的公众号。 专注于基础架构和 Linux。 十年架构,每天百亿流量,与你探讨高并发世界,给你不一样的滋味。 我的个人微信xjjdog0,欢迎加好友进一步交流。