看过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方法的更多相关文章

  1. 聊聊高并发(二十)解析java.util.concurrent各个组件(二) 12个原子变量相关类

    这篇说说java.util.concurrent.atomic包里的类,总共12个.网上有非常多文章解析这几个类.这里挑些重点说说. watermark/2/text/aHR0cDovL2Jsb2cu ...

  2. 聊聊高并发(二十八)解析java.util.concurrent各个组件(十) 理解ReentrantReadWriteLock可重入读-写锁

    这篇讲讲ReentrantReadWriteLock可重入读写锁,它不仅是读写锁的实现,而且支持可重入性. 聊聊高并发(十五)实现一个简单的读-写锁(共享-排他锁) 这篇讲了怎样模拟一个读写锁. 可重 ...

  3. 聊聊高并发(二十五)解析java.util.concurrent各个组件(七) 理解Semaphore

    前几篇分析了一下AQS的原理和实现.这篇拿Semaphore信号量做样例看看AQS实际是怎样使用的. Semaphore表示了一种能够同一时候有多个线程进入临界区的同步器,它维护了一个状态表示可用的票 ...

  4. 聊聊高并发(三十四)Java内存模型那些事(二)理解CPU快速缓存的工作原理

    在上一篇聊聊高并发(三十三)从一致性(Consistency)的角度理解Java内存模型 我们说了Java内存模型是一个语言级别的内存模型抽象.它屏蔽了底层硬件实现内存一致性需求的差异,提供了对上层的 ...

  5. 聊聊高并发(二十九)解析java.util.concurrent各个组件(十一) 再看看ReentrantReadWriteLock可重入读-写锁

    上一篇聊聊高并发(二十八)解析java.util.concurrent各个组件(十) 理解ReentrantReadWriteLock可重入读-写锁 讲了可重入读写锁的基本情况和基本的方法,显示了怎样 ...

  6. 聊聊高并发(三十二)实现一个基于链表的无锁Set集合

    Set表示一种没有反复元素的集合类,在JDK里面有HashSet的实现,底层是基于HashMap来实现的.这里实现一个简化版本号的Set,有下面约束: 1. 基于链表实现.链表节点依照对象的hashC ...

  7. 高并发第八弹:J.U.C起航(java.util.concurrent)

    java.util.concurrent是JDK自带的一个并发的包主要分为以下5部分: 并发工具类(tools) 显示锁(locks) 原子变量类(aotmic) 并发集合(collections) ...

  8. 从SpringBoot构建十万博文聊聊高并发文章浏览量设计

    前言 在经历了,缓存.限流.布隆穿透等等一系列加强功能,十万博客基本算是成型,网站上线以后也加入了百度统计来见证十万+ 的整个过程. 但是百度统计并不能对每篇博文进行详细的浏览量统计,如果做一些热点博 ...

  9. java高并发----个人学习理解汇总记录

    1.首先,需要理解几个概念 1.同步(Synchronous):同步方法调用一旦开始,调用者必须等到前面的方法调用返回后,才能继续后续的行为,依次直到完成所有. 2.异步(Asynchronous): ...

随机推荐

  1. matplotlib 可视化 —— 绘制常见图形

    0. 饼状图 plt.pie():Python数据可视化:饼状图 1. 三角形 描点连线,起点和终点相同 triangle1 = ((0, sqrt(3)/2), (1, 3*sqrt(3)/2), ...

  2. java9新特性-14-多分辨率图像 API

    1.官方Feature 251: Multi-Resolution Images 263: HiDPI Graphics on Windows and Linux 2.产生背景 在Mac上,JDK已经 ...

  3. 前端之HTTP协议

    HTTP协议简介 作为学习前端开发的开始,我们必须搞明白以下几件事 1.什么是互联网      互联网=物理连接介质+互联网协议     2.互联网建立的目的? 数据传输打破地域限制,否则的话,我想获 ...

  4. mysql去掉密码规则的两种方式

    环境介绍:centeros 7 + mysqld5.7 当我们装完数据库以后,使用临时密码登录到数据库去更改一个简单的密码,如 set password='; 结果出现以下提示: ERROR (HY0 ...

  5. WebService通讯技术的CXF框架问题

    WebService通讯技术的CXF框架问题 严重: Servlet /cxf_rs_spring threw load() exception java.lang.ClassCastExceptio ...

  6. CMDB学习之六 --客户端请求测试,服务端api优化

    客户端使用agent 请求测试,agent使用的POST 请求,使用requests模块 本地采集,汇报服务端 #!/usr/bin/env python # -*- coding:utf-8 -*- ...

  7. 20180929 北京大学 人工智能实践:Tensorflow笔记05

    (完)

  8. Python学习笔记(2)--基本数据类型

    在介绍基本数据类型之前,先说一个系统方法type():返回对象的数据类型,可以帮助我们查看系统的类型定义 python不同的版本,类型名称稍有不同,这里使用的是3.5.2版本 一.基本数据类型: 1. ...

  9. select &amp; epoll

    同步.异步.堵塞和非堵塞差别 同步:发出一个功能调用时.在没有得到结果之前,该调用就不返回 异步:当一个异步过程调用发出后.调用者不能立马得到结果.实际处理这个调用的部件在完毕后.通过状态.通知和回调 ...

  10. [Recompose] Make Reusable React Props Streams with Lenses

    If you hard-code a stream of props to target a specific prop, it becomes impossible to reuse that st ...