threadlocal

BAT面试必考:ThreadLocal,ThreadLocalMap 和Thread 的关系

狂风中的少年 提交于 2019-12-18 03:50:49
引言 这三种的关系由于大量的内部类的关系,第一次看的时候还是有点绕的,感觉你是老子的孙子,又是老子的老子。我还是建议你先抛开内部类的关系,把每一个类当作普通类来看到,理解每個类的职责,最后再把内部类放进去考虑这样设计的目的。这里也给大家一个启示,面对复杂的事情的时候,我们需要跳出来,先把问题简单化,大方向把握了,再进一步去细化每一个功能点和设计的艺术。 关系图解 接下来我们看下面一张图 从上图我们可以发现Thread 中持有一个ThreadLocalMap ,这里你可以简单理解为就是持有一个数组,这个数组是Entry 类型的。 Entry 的key 是ThreadLocal 类型的,value 是Object 类型。也就是一个ThreadLocalMap 可以持有多个ThreadLocal。他们是一对多的关系(当然Entry 还涉及到弱引用的技术,这里不展开,不然就没完没了了) 加上内部类的关系 为什么ThreadLocalMap 设计为ThreadLocal 内部类 看到各种内部类是不是有点晕,感觉你是老子的孙子,又是老子的老子,为什么不独立ThreadLocalMap 出来呢?其实这里涉及到内部类起到封装的作用。来,我们看看源码的解析 主要是说明ThreadLocalMap 是一个线程本地的值,它所有的方法都是private 的,也就意味着除了ThreadLocal 这个类

什么时候以及如何使用ThreadLocal变量?

人走茶凉 提交于 2019-12-17 22:10:10
【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>> 什么时候应该使用 ThreadLocal 变量? 如何使用? #1楼 您必须非常谨慎地使用ThreadLocal模式。 有一些主要的缺点,例如Phil提到的,但没有提到的一个是确保设置ThreadLocal上下文的代码不是“可重入的”。 当设置信息的代码第二次或第三次运行时,可能会发生不好的事情,因为线程上的信息可能在您不期望的时候开始发生变异。 因此,在再次设置之前,请确保未设置ThreadLocal信息。 #2楼 这里没有什么新鲜的东西,但是我今天发现,在Web应用程序中使用Bean验证时, ThreadLocal 非常有用。 验证消息已本地化,但默认情况下使用 Locale.getDefault() 。 您可以使用其他 MessageInterpolator 配置 Validator ,但是在调用 validate 时无法指定 Locale 。 因此,您可以创建一个静态 ThreadLocal<Locale> (或者更好的是,一个具有其他内容的常规容器,您可能需要成为 ThreadLocal ,然后让您的自定义 MessageInterpolator 从中选择 Locale 。下一步是编写一个使用会话的 ServletFilter value或 request.getLocale()

Java 多线程之自旋锁

不羁的心 提交于 2019-12-17 15:17:08
一、什么是自旋锁? 自旋锁(spinlock):是指当一个线程在获取锁的时候,如果锁已经被其它线程获取,那么该线程将循环等待,然后不断的判断锁是否能够被成功获取,直到获取到锁才会退出循环。 获取锁的线程一直处于活跃状态,但是并没有执行任何有效的任务,使用这种锁会造成 busy-waiting 。 它是为实现保护共享资源而提出一种锁机制。其实,自旋锁与互斥锁比较类似,它们都是为了解决对某项资源的互斥使用。无论是互斥锁,还是自旋锁,在任何时刻,最多只能有一个保持者,也就说,在任何时刻最多只能有一个执行单元获得锁。但是两者在调度机制上略有不同。对于互斥锁,如果资源已经被占用,资源申请者只能进入睡眠状态。但是自旋锁不会引起调用者睡眠,如果自旋锁已经被别的执行单元保持,调用者就一直循环在那里看是否该自旋锁的保持者已经释放了锁,”自旋”一词就是因此而得名。 二、Java如何实现自旋锁? 下面是个简单的例子: public class SpinLock { private AtomicReference<Thread> cas = new AtomicReference<Thread>(); public void lock() { Thread current = Thread.currentThread(); // 利用CAS while (!cas.compareAndSet(null,

java自旋锁

十年热恋 提交于 2019-12-17 14:49:39
什么是自旋锁? 自旋锁(spinlock) :是指当一个线程在获取锁的时候,如果锁已经被其它线程获取,那么该线程将循环等待,然后不断的判断锁是否能够被成功获取,直到获取到锁才会退出循环。 获取锁的线程一直处于活跃状态,但是并没有执行任何有效的任务,使用这种锁会造成busy-waiting。 Java如何实现自旋锁? 下面是个简单的例子: /** * Date: 2016年1月4日 下午4:41:50 * * @author medusar */ public class SpinLock { private AtomicReference cas = new AtomicReference(); public void lock() { Thread current = Thread.currentThread(); // 利用CAS while (!cas.compareAndSet(null, current)) { // DO nothing } } public void unlock() { Thread current = Thread.currentThread(); cas.compareAndSet(current, null); } } ock()方法利用的CAS,当第一个线程A获取锁的时候,能够成功获取到,不会进入while循环,如果此时线程A没有释放锁

ThreadLocal为什么会内存泄漏

假装没事ソ 提交于 2019-12-17 08:13:52
ThreadLocal的原理:每个Thread内部维护着一个ThreadLocalMap,它是一个Map。这个映射表的Key是一个 弱引用 ,其实就是ThreadLocal本身,Value是真正存的线程变量Object。 ThreadLocal在ThreadLocalMap中是以一个弱引用身份被Entry中的Key引用的,因此如果ThreadLocal没有外部强引用来引用它,那么ThreadLocal会在下次JVM垃圾收集时被回收。这个时候就会出现Entry中Key已经被回收,出现一个null Key的情况,外部读取ThreadLocalMap中的元素是无法通过null Key来找到Value的。因此如果当前线程的生命周期很长,一直存在,那么其内部的ThreadLocalMap对象也一直生存下来,这些null key就存在一条强引用链的关系一直存在:Thread --> ThreadLocalMap-->Entry-->Value,这条强引用链会导致Entry不会回收,Value也不会回收,但Entry中的Key却已经被回收的情况,造成内存泄漏。 但是JVM团队已经考虑到这样的情况,并做了一些措施来保证ThreadLocal尽量不会内存泄漏:在ThreadLocal的get()、set()、remove(

Java并发编程:深入剖析ThreadLocal

断了今生、忘了曾经 提交于 2019-12-16 15:59:53
【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>> 想必很多朋友对ThreadLocal并不陌生,今天我们就来一起探讨下ThreadLocal的使用方法和实现原理。首先,本文先谈一下对ThreadLocal的理解,然后根据ThreadLocal类的源码分析了其实现原理和使用需要注意的地方,最后给出了两个应用场景。   以下是本文目录大纲:   一.对ThreadLocal的理解   二.深入解析ThreadLocal类   三.ThreadLocal的应用场景   若有不正之处请多多谅解,并欢迎批评指正。   请尊重作者劳动成果,转载请标明原文链接:    http://www.cnblogs.com/dolphin0520/p/3920407.html 一.对ThreadLocal的理解 ThreadLocal,很多地方叫做线程本地变量,也有些地方叫做线程本地存储,其实意思差不多。可能很多朋友都知道ThreadLocal为变量在每个线程中都创建了一个副本,那么每个线程可以访问自己内部的副本变量。   这句话从字面上看起来很容易理解,但是真正理解并不是那么容易。   我们还是先来看一个例子: class ConnectionManager { private static Connection connect = null; public static

被大厂面试官连环炮轰炸的ThreadLocal (吃透源码的每一个细节和设计原理)

走远了吗. 提交于 2019-12-15 01:32:40
引言 ThreadLocal 是面试过程中非常高频的一个类,这类的复杂程度绝对是可以带出一系列连环炮的面试轰炸。biu biu biu ~~~~. 一直觉得自己对这个类很了解了,但是直到去看源码,接二连三的技术浮出水面(弱引用,避免内存溢出的操作,开放地址法解决hash 冲突,各种内部类的复杂的关系),看到你怀疑人生,直到根据代码一步一步的画图才最终理解(所以本篇文章会有大量的图)。 这里也给大家一个启示,面对复杂的事情的时候,实在被问题绕晕了,就画图吧,借助图可以让问题可视化,便于理解。 WHAT ThreadLocal 是一个线程的本地变量,也就意味着这个变量是线程独有的,是不能与其他线程共享的,这样就可以避免资源竞争带来的多线程的问题,这种解决多线程的安全问题和lock(这里的lock 指通过synchronized 或者Lock 等实现的锁) 是有本质的区别的: lock 的资源是多个线程共享的,所以访问的时候需要加锁。 ThreadLocal 是每个线程都有一个副本,是不需要加锁的。 lock 是通过时间换空间的做法。 ThreadLocal 是典型的通过空间换时间的做法。 当然他们的使用场景也是不同的,关键看你的资源是需要多线程之间共享的还是单线程内部共享的 使用 ThreadLocal 的使用是非常简单的,看下面的代码 public class Test {

ThreadLocal面试六连问

佐手、 提交于 2019-12-14 11:30:31
ThreadLocal为Java并发提供了一个新的思路, 它用来存储Thread的局部变量, 从而达到各个Thread之间的隔离运行。它被广泛应用于框架之间的用户资源隔离、事务隔离等。 但是用不好会导致内存泄漏, 本文重点用于对它的使用过程的疑难解答, 相信仔细阅读完后的朋友可以随心所欲的安全使用它。 一、内存泄漏原因探索 ThreadLocal操作不当会引发内存泄露,最主要的原因在于它的内部类ThreadLocalMap中的Entry的设计。 Entry继承了WeakReference<ThreadLocal<?>>,即Entry的key是弱引用,所以key’会在垃圾回收的时候被回收掉, 而key对应的value则不会被回收, 这样会导致一种现象:key为null,value有值。 key为空的话value是无效数据,久而久之,value累加就会导致内存泄漏。 二、怎么解决这个内存泄漏问题 每次使用完ThreadLocal都调用它的remove()方法清除数据。因为它的remove方法会主动将当前的key和value(Entry)进行清除。 e.clear()用于清除Entry的key,它调用的是WeakReference中的方法:this.referent = null expungeStaleEntry(i)用于清除Entry对应的value, 这个后面会详细讲。 三

深入JDK源码分析ThreadLocal

橙三吉。 提交于 2019-12-14 00:52:56
深入源码JDK分析ThreadLocal ThreadLocal为当前线程创建和维护变量副本,并对其他线程不可见,确保线程安全,本文通过探究源码来深入了解其原理. 先看set()方法的实现: public void set ( T value ) { Thread t = Thread . currentThread ( ) ; //从当前线程Thread中获取ThreadLocalMap实例。 ThreadLocalMap map = getMap ( t ) ; if ( map != null ) //ThreadLocal实例和value封装成Entry。 map . set ( this , value ) ; else createMap ( t , value ) ; } ThreadLocalMap getMap ( Thread t ) { return t . threadLocals ; } 看看map.set()方法如何将Entry存入table数组: private void set ( ThreadLocal < ? > key , Object value ) { Entry [ ] tab = table ; int len = tab . length ; //通过ThreadLocal的nextHashCode方法生成hash值 //通过

多线程并发神器--ThreadLocal

∥☆過路亽.° 提交于 2019-12-12 06:07:11
什么是ThreadLocal 可以理解成线程本地变量,传统的线程对一个变量操作时操作的是同一个对象,也存在线程安全的问题。 ThreadLocal是一个变量的本地副本,线程对变量的操作不会影响其他线程。 首先看看ThreadLocal的类结构 其中可重写的方法有以下几个 initialValue():ThreadLocal初始化的值,新建ThreadLocal的一般要重写给个初始的值。 get():获取当前线程变量的副本值。 set(T value):设置、更新当前线程上的变量副本值。 remove():移除当前线程上的变量副本。 ThreadLocal使用 新建ThreadLocal,类型为User,并初始化为tom,12岁,启动3个线程,每个线程循环3次,休眠1少,主线程再输出。 输出结果如下 从结果可见每个线程使用的是各自线程的变量副本,并没有影响其他线程和主线程,实现了线程隔离的效果。 使用场景 一般用来解决数据库连接、用户session管理等。 内存泄露问题 如果线程的执行周期过长可能导致内存泄露的风险,虽然线程执行完后会ThreadLocal也会随着销毁,但最好使用完后加上remove这样会加快内存的释放,一般来说线程周期不长是不太会引起内存泄露的。还有如果定义了ThreadLocal又不用也有问题,因为每次ThreadLocal的get/set