volatile
- 一个变量修饰符,只能用来修饰变量,可以保证有序性和可见性,但是不能保证原子性,最常见的问题就是i++,他分为三个操作,在主内存中拿到原始值,进行增加,然后从工作内存写回主内存,多个线程并发执行的时候可能会有回写主内存覆盖问题。想要解决可以使用Atomic类,比如AtomicInteger,AtomicLong,AtomincReference,这些类核心是基于这个CAS机制,能把读,改,写三步合并成异步进行
- 保证可见性:当一个变量被声明为volatile的时候,他会保证对这个变量的写操作会立即刷新到主内存中,而且对这个变量的读操作会直接从主内存中读取。可见性产生的原因:由于CPU和这个内存处理上面存在一定差别,所以在这个CPU和主内存之间增加了多级高速缓存,L1,L2,L3.但是多级缓存就会带来一个数据一致性的问题,所有就通过一个缓存一致性协议来解决,比较常见的就是MESI协议,M表示数据被修改,和内存中的数据不一致,数据只存在本cache中,E和S都表示数据和内存中的数据一致,但是E是数据保存在本cache,S是存在很多个Cache中,I表示这个数据无效。当这个数据处理缓存行的时候就会先检查这个缓存行状态,这个主要是在硬件层面处理CPU缓存之间的一致性.
- 禁止指令重排:指令重排序是指令编写的顺序和执行的顺序是不一致的,从而在多线程条件下产生可见性问题,这个操作本来是一种CPU性能优化的手段,他引入了一个叫做storeBuffer的机制,,这种优化机制会导致CPU的乱序执行,但是他也提供了内存屏障指令,上层应用可以在合适的地方插入这个内存屏障,从而避免这个指令重排序的问题。
ThreadLocal
- 这是一种解决线程安全的机制,为每一个线程创建一个共享变量副本来保证各个线程之间的一个访问和修改互不影响,也可以避免死锁
- 他的实现依赖于一个ThreadLocalMap,每个变量都有这样一个实例,主要有四个方法,initialValue(返回局部变量的初始值),get,set,remove。当调用这个get方法的时候会先检查ThreadLocal中是否有与之关联的值,如果没有调用这个initalValue方法初始化该值,remove方法清楚ThreadLocal变量,如果没有及时清理会产生内存泄漏问题
- 产生这个内存泄漏主要是ThreadLocalMap的key-value部分,这里key就是Threadlocal对象,主要有两个引用源,一个是栈上的ThreadLocal引用,还有一个是来自ThreadLocalMap中key对他的一个引用,所以有引用链存在,像是这个ThreadLocal在线程池中被反复使用,就会导致这个对象没办法被回收。这对这个问题,在ThreadLocalMap的那条引用链采用了弱引用,能保证被GC回收。但是如果这个在线程池中还有一条引用没办法被回收掉,所以最好的办法就是我们在使用完之后手动使用remove
- 但是在这个JDK21好像就有一个scopedValue就很好的解决了这个ThreadLocal的内存泄漏问题,只要是通过将数据绑定到代码执行的一个作用域而不是整个线程了,在作用域内执行完任务之后就自动清理掉绑定的值。
posted @
2025-12-10 15:35
Huangyien
阅读(
0)
评论()
收藏
举报