聊聊高并发(十八)理解AtomicXXX.lazySet方法
看过java.util.concurrent.atomic包里面各个AtomicXXX类实现的同学应该见过lazySet方法。比方AtomicBoolean类的lazySet方法
public final void lazySet(boolean newValue) {
int v = newValue ? 1 : 0;
unsafe.putOrderedInt(this, valueOffset, v);
}
它的底层实现调用了Unsafe的putOrderedInt方法。来看看putOrderedXXX方法的JavaDoc
它的意思是putOrderedXXX方法是putXXXVolatile方法的延迟实现,不保证值的改变被其它线程马上看到
<span><span><span style="font-family:Calibri;font-size:12px;"> /***
* Sets the value of the integer field at the specified offset in the
* supplied object to the given value. This is an ordered or lazy
* version of <code>putIntVolatile(Object,long,int)</code>, which
* doesn't guarantee the immediate visibility of the change to other
* threads. It is only really useful where the integer field is
* <code>volatile</code>, and is thus expected to change unexpectedly.
* 设置obj对象中offset偏移地址相应的整型field的值为指定值。这是一个有序或者
* 有延迟的<code>putIntVolatile</cdoe>方法。而且不保证值的改变被其它线程立
* 即看到。仅仅有在field被<code>volatile</code>修饰而且期望被意外改动的时候
* 使用才实用。 *
* @param obj the object containing the field to modify.
* 包括须要改动field的对象
* @param offset the offset of the integer field within <code>obj</code>.
* <code>obj</code>中整型field的偏移量
* @param value the new value of the field.
* field将被设置的新值
* @see #putIntVolatile(Object,long,int)
*/</span></span></span>
<span><span><span style="font-family:Calibri;font-size:12px;"> public native void putOrderedInt(Object obj, long offset, int value);</span></span></span>
理解volatile底层实现的同学知道,volatile的实现终于是加了内存屏障,
1. 保证写volatile变量会强制把CPU写缓存区的数据刷新到内存
2. 读volatile变量时,使缓存失效。强制从内存中读取最新的值
3. 由于内存屏障的存在,volatile变量还能阻止重排序
所以volatile变量的改动能够立马让全部的线程可见,保证了可见性。
而不加volatile变量的字段。JMM不保证普通变量的改动立马被全部的线程可见。所以lazySet说白了就是以普通变量的方式来写变量。
// 对flagA的改动对全部线程立马可见
volatile boolean flagA;
// 对flagB的改动不能立马被其它线程可见
boolean flagB;
那么为什么须要lazySet方法呢?事实上它是一种低级别的优化手段,对上层调用者来说。事实上非常少用到。以下说说用lazySet的一个场景。
在这篇 聊聊高并发(十六)实现一个简单的可重入锁 中我们实现了一个可重入锁。里面共享变量用了volatile变量,来保证对共享变量的改动对其它线程可见。
可是事实上,这里全然能够不用volatile变量来修饰这些共享状态。
1. 由于訪问共享状态之前先要获得锁, Lock.lock()方法能够获得锁,而获得锁的操作和volatile变量的读操作一样,会强制使CPU缓存失效,强制从内存读取变量。
2. Lock.unlock()方法释放锁时。和写volatile变量一样,会强制刷新CPU写缓冲区。把缓存数据写到主内存
底层也是通过加内存屏障实现的。
package com.zc.lock; import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock; /**
* 简单的可重入锁实现,使用一个计数器记录当前线程重入锁的次数,获得锁时计数器加1,释放锁时计数器减1。当计数器等于0时表示释放了锁
* **/
public class SimpleReentrantLock implements Lock{ // 指向已经获得锁的线程
private volatile Thread exclusiveOwnerThread; // 记录获取了同一个锁的次数
private volatile int holdCount; private final java.util.concurrent.locks.Lock lock; // 是否是自己获得锁的条件
private final Condition isCountZero; public SimpleReentrantLock(){
lock = new ReentrantLock();
isCountZero = lock.newCondition();
holdCount = 0;
} @Override
public void lock() {
lock.lock();
try{
// 当前线程的引用
Thread currentThread = Thread.currentThread();
// 假设获得锁的线程是自己。那么计数器加1,直接返回
if(exclusiveOwnerThread == currentThread){
holdCount ++;
return;
} while(holdCount != 0){
try {
isCountZero.await();
} catch (InterruptedException e) {
throw new RuntimeException("Interrupted");
}
}
// 将exclusiveOwnerThread设置为自己
exclusiveOwnerThread = currentThread;
holdCount ++;
}finally{
lock.unlock();
}
}
而lazySet()的使用方法和上面的优化是一个道理,就是在不须要让共享变量的改动立马让其它线程可见的时候,以设置普通变量的方式来改动共享状态,能够降低不必要的内存屏障,从而提高程序运行的效率。
以下的样例来自StackOverflow上的一个提问,说的也是相似的意思,就是优化不必要的volatile操作。
被墙的同学看不到。能够看截图。
聊聊高并发(十八)理解AtomicXXX.lazySet方法的更多相关文章
- 聊聊高并发(二十)解析java.util.concurrent各个组件(二) 12个原子变量相关类
这篇说说java.util.concurrent.atomic包里的类,总共12个.网上有非常多文章解析这几个类.这里挑些重点说说. watermark/2/text/aHR0cDovL2Jsb2cu ...
- 聊聊高并发(二十八)解析java.util.concurrent各个组件(十) 理解ReentrantReadWriteLock可重入读-写锁
这篇讲讲ReentrantReadWriteLock可重入读写锁,它不仅是读写锁的实现,而且支持可重入性. 聊聊高并发(十五)实现一个简单的读-写锁(共享-排他锁) 这篇讲了怎样模拟一个读写锁. 可重 ...
- 聊聊高并发(二十五)解析java.util.concurrent各个组件(七) 理解Semaphore
前几篇分析了一下AQS的原理和实现.这篇拿Semaphore信号量做样例看看AQS实际是怎样使用的. Semaphore表示了一种能够同一时候有多个线程进入临界区的同步器,它维护了一个状态表示可用的票 ...
- 聊聊高并发(三十四)Java内存模型那些事(二)理解CPU快速缓存的工作原理
在上一篇聊聊高并发(三十三)从一致性(Consistency)的角度理解Java内存模型 我们说了Java内存模型是一个语言级别的内存模型抽象.它屏蔽了底层硬件实现内存一致性需求的差异,提供了对上层的 ...
- 聊聊高并发(二十九)解析java.util.concurrent各个组件(十一) 再看看ReentrantReadWriteLock可重入读-写锁
上一篇聊聊高并发(二十八)解析java.util.concurrent各个组件(十) 理解ReentrantReadWriteLock可重入读-写锁 讲了可重入读写锁的基本情况和基本的方法,显示了怎样 ...
- 聊聊高并发(三十二)实现一个基于链表的无锁Set集合
Set表示一种没有反复元素的集合类,在JDK里面有HashSet的实现,底层是基于HashMap来实现的.这里实现一个简化版本号的Set,有下面约束: 1. 基于链表实现.链表节点依照对象的hashC ...
- 高并发第八弹:J.U.C起航(java.util.concurrent)
java.util.concurrent是JDK自带的一个并发的包主要分为以下5部分: 并发工具类(tools) 显示锁(locks) 原子变量类(aotmic) 并发集合(collections) ...
- 从SpringBoot构建十万博文聊聊高并发文章浏览量设计
前言 在经历了,缓存.限流.布隆穿透等等一系列加强功能,十万博客基本算是成型,网站上线以后也加入了百度统计来见证十万+ 的整个过程. 但是百度统计并不能对每篇博文进行详细的浏览量统计,如果做一些热点博 ...
- java高并发----个人学习理解汇总记录
1.首先,需要理解几个概念 1.同步(Synchronous):同步方法调用一旦开始,调用者必须等到前面的方法调用返回后,才能继续后续的行为,依次直到完成所有. 2.异步(Asynchronous): ...
随机推荐
- zzulioj--1804--ZY学长的密码(字符串)
1804: ZY学长的密码 Time Limit: 1 Sec Memory Limit: 128 MB Submit: 140 Solved: 53 SubmitStatusWeb Board ...
- Linux 命令行光标快速选中移动快捷键
Ctrl+Alt+T 打开终端一些常用的终端快捷键:Ctrl+L 清空屏幕(功能相当于命令clear)Ctrl+U 剪切文本直到行的起始(可以用于清空行)Ctrl+K 剪切文本直到行的末尾Ctrl+Y ...
- CSS提高渲染速度的写法
写CSS的习惯,决定页面渲染速度的快慢,这一点在脑残的IE里更加明显.养成良好的习惯,乃至形成规范,会让你的页面更快速的加载,用户体验度更高,下面是零度逍遥总结的一些提高CSS渲染速度的写法,供大家参 ...
- Python开源爬虫项目代码:抓取淘宝、京东、QQ、知网数据--转
数据来源:数据挖掘入门与实战 公众号: datadw scrapy_jingdong[9]- 京东爬虫.基于scrapy的京东网站爬虫,保存格式为csv.[9]: https://github.co ...
- python2中打印列表与字典内的中文字符
在开发过程中,我们经常需要打印一些变量的值,便于调试.这个时候就会发现如果在列表与字典这些容器中,如果包含中文字符,不管是str类型,还是unicode类型,都打印不出来.如下: >>&g ...
- WSGI和CGI
https://www.zhihu.com/question/19998865 https://segmentfault.com/a/1190000003069785
- ArcGIS api for javascript——显示一个信息窗口
描述 这个示例展示了在用户单击地图时如何在InfoWindow中显示信息.信息窗口是一个dijit (Dojo widget).信息窗口能够包含文本,字符,图片和任何通过HTML表示的事物.这个例子在 ...
- hdu 1757 矩阵连乘
- HDU 1730 Northcott Game
简单的尼姆博弈.想到了非常easy! 就拿一行举例.怎么赢.? 就是死劲挨着对方移,当然假设本身就是挨着的,又轮到你移动了,那么对于这一行来讲.你就是输的!! 由此可见每一行的棋子起始距离就显得尤为重 ...
- Delegates, Events, and Anonymous Methods 委托、事件与匿名方法
http://www.cnblogs.com/r01cn/archive/2012/11/30/2795977.html