Java并发程序设计(七)乐天派:无锁
无锁
一、概述
无锁是处理并发的一种乐观策略,它会假设对资源的访问是没有冲突的。既然没有冲突自然不需要等待,所以所有的线程都可以在不停顿的状态下执行。那遇到冲突怎么办?接下来请看,无锁绝招“CAS”即比较交换术。
二、CAS原理
CAS即Compare and swap.其算法过程是这样的:它有三个参数:
1.V表示要更新的变量
2.E表示期望值
3.N表示新值
仅当V等于E时,才会将V设为N。如果V和N不同,则说明有其他线程做了更新,则该线程什么都不做。当多个线程同时使用CAS进行变量操作时,只有一个会更新成功,其余都会失败。失败的线程不会被挂起,而是进行重试。
三、无锁的线程安全整数:AtomicInteger
AtomicInteger主要方法如下(对于其他无锁线程安全类,其方法类似):
public final int get() //取得当前值
public final void set(int newValue) //设置当前值
public final int getAndset(int newValue) //设置新值返回旧值
public final boolean compareAndSet(int except,int u) //如果当前值为except则设为u
public final int getAndIncrement() //当前值加1返回旧值
public final int getAndDecrement()
public final int getAndAdd(int delta)
public final int incrementAndGet()
public final int decrementAndGet()
public final int addAndGet()
就AtomicInteger核心字段:
private volatile int value; //代表AtomicInteger当前的值
private static final long valueOffset; //value字段的偏移量
AtomicInteger的使用示例:
public class AutomicIntegerDemo {
static AtomicInteger i=new AtomicInteger();
public static class addThread implements Runnable{
@Override
public void run() {
for(int j=0;j<1000;j++){
i.incrementAndGet();
}
}
}
public static void main(String[] args) throws InterruptedException {
Thread[] ts=new Thread[10];
for(int j=0;j<10;j++){
ts[j]=new Thread(new addThread());
}
for(int j=0;j<10;j++) ts[j].start();
for (int j=0;j<10;j++) ts[j].join();
System.out.println(i);
}
}
相比使用锁,使用无锁会有更好的性能。
四、CAS算法逻辑上瑕疵及解决办法:AtomicStampedReference
CAS算法逻辑上的瑕疵:当你获得对象当前数据后,在准备修改为新值前,对象的值被其他对象连续修改了两次,而经过这两次修改后,对象的值又恢复到旧值。这样,当前线程就无法判断该值是否被修改过。也就是说你修改的对象数值没有过程状态信息。
AtomicStampedReference内部不仅维护了对象值还维护了一个状态值。
五、无锁数组
当前可用的原子数组有:AtomicIntegerArray,AtomicLongArray和AtomicReferenceArray
public class AtomicIntegerArrayDemo {
static AtomicIntegerArray array=new AtomicIntegerArray(10);
public static class addThread implements Runnable{
@Override
public void run() {
for (int j=0;j<1000;j++){
array.getAndIncrement(j%array.length());
}
}
}
public static void main(String[] args) throws InterruptedException {
Thread[] ts=new Thread[10];
for (int j=0;j<10;j++){
ts[j]=new Thread(new addThread());
}
for (int j=0;j<10;j++) ts[j].start();
for (int j=0;j<10;j++) ts[j].join();
System.out.println(array);
}
}
六、让普通变量也享受原子操作:AtomicIntegerFieldUpdater
public class AtomicIntegerFieldUpdaterDemon {
public static class Candidate{
int id;
volatile int score;
}
public final static AtomicIntegerFieldUpdater<Candidate> scoreUpdater=
AtomicIntegerFieldUpdater.newUpdater(Candidate.class,"score");
public static AtomicInteger checkScore=new AtomicInteger(0); //用于检测
public static void main(String[] args) throws InterruptedException {
final Candidate candidate=new Candidate();
Thread[] threads=new Thread[1000];
for (int i=0;i<1000;i++){
threads[i]=new Thread(){
public void run(){
if (Math.random()>0.4){
scoreUpdater.incrementAndGet(candidate);
checkScore.incrementAndGet();
}
}
};
threads[i].start();
}
for (int i=0;i<1000;i++) threads[i].join();
System.out.println("score="+candidate.score);
System.out.println("checkScore="+checkScore);
}
}
注意事项:
1.Updater只能修改可见范围内的变量。
2.变量必须是volatile
3.变量不能是static的
Java并发程序设计(七)乐天派:无锁的更多相关文章
- 【实战Java高并发程序设计 2】无锁的对象引用:AtomicReference
AtomicReference和AtomicInteger非常类似,不同之处就在于AtomicInteger是对整数的封装,而AtomicReference则对应普通的对象引用.也就是它可以保证你在修 ...
- Java并发程序设计(十三)锁的性能优化
锁的性能优化 一.优化注意事件 一)减少锁的持有时间 只在必要时进行同步,能明显减少锁的持有时间. 二)锁的细化 缺陷:当系统需要全局锁时,其消耗的资源会比较多. 三)锁的分离 比如读写分离锁 四)锁 ...
- Java并发基础:了解无锁CAS就从源码分析
https://segmentfault.com/a/1190000015881923
- Java并发程序设计(一) 基础概念
Java并发程序设计(一) 基础概念 一.必须知道的几个概念 一)同步(Synchronous)和异步(Asynchronous) 同步:同步方法调用一旦开始,调用者必须等到方法调用返回后,才能继续后 ...
- Java并发编程实战 03互斥锁 解决原子性问题
文章系列 Java并发编程实战 01并发编程的Bug源头 Java并发编程实战 02Java如何解决可见性和有序性问题 摘要 在上一篇文章02Java如何解决可见性和有序性问题当中,我们解决了可见性和 ...
- java并发笔记之synchronized 偏向锁 轻量级锁 重量级锁证明
警告⚠️:本文耗时很长,先做好心理准备 本篇将从hotspot源码(64 bits)入手,通过分析java对象头引申出锁的状态:本文采用大量实例及分析,请耐心看完,谢谢 先来看一下hotspot的 ...
- Java并发编程:synchronized和锁优化
1. 使用方法 synchronized 是 java 中最常用的保证线程安全的方式,synchronized 的作用主要有三方面: 确保线程互斥的访问代码块,同一时刻只有一个方法可以进入到临界区 保 ...
- java并发笔记之证明 synchronized锁 是否真实存在
警告⚠️:本文耗时很长,先做好心理准备 证明:偏向锁.轻量级锁.重量级锁真实存在 由[java并发笔记之java线程模型]链接: https://www.cnblogs.com/yuhangwang/ ...
- 【Java并发系列04】线程锁synchronized和Lock和volatile和Condition
img { border: solid 1px } 一.前言 多线程怎么防止竞争资源,即防止对同一资源进行并发操作,那就是使用加锁机制.这是Java并发编程中必须要理解的一个知识点.其实使用起来还是比 ...
随机推荐
- ll(ls -l) 列属性
文件属性 文件数 拥有者 所属的group 文件大小 建档日期 文件名 drwx------ 2 Guest users 1024 Nov 21 21:05 Mail
- 解析如何在C语言中调用shell命令的实现方法【转】
本文转自:http://www.jb51.net/article/37404.htm 1.system(执行shell 命令)相关函数 fork,execve,waitpid,popen表头文件 #i ...
- C++:greater<int>和less<int>
greater和less是xfunctional.h中的两个结构体,代码如下: template<class _Ty = void> struct less { // functor fo ...
- openwrt git 代码下载地址
openwrt 各个版本代码下载 trunk:git clone git://github.com/openwrt/openwrt.git 15.05 (Chaos Calmer)git clone ...
- zabbix3.0.4报错Get value from agent failed: cannot connect to [[1.1.1.1]:10050]: [4] Interrupted syste
一.问题描述 部署完Zabbix agent之后,Server无法获取到数据.报错.报错信息如下: Get value from agent failed: cannot connect to [[1 ...
- Go语言学习之路(持续更新中)
菜鸟 Go语言教程 教程(RUNOOB.COM):http://www.runoob.com/go/go-tutorial.html Go全球官网:https://golang.org/ (2018- ...
- JavaScript 使用 mediaDevices API 选择摄像头
大多数智能手机都有前置和后置摄像头,当你在创建视频应用时你可能想要选择或者切换前置.后置摄像头. 如果你开发的是一款聊天应用,你很可能会想调用前置摄像头,但如果你开发的是一款拍照软件,那么你会更倾向于 ...
- Linux C 结构体初始化三种形式
最近看linux代码时发现了结构体 struct 一种新的初始化方式,各方查找对比后总结如下: 1. 顺序初始化教科书上讲C语言结构体初始化是按照顺序方式来讲的,没有涉及到乱序的方式.顺序初始化str ...
- Laravel Form 表单的数据校验
例如,要使用手机号加验证码的方式提供登录网站的功能,那么在处理前端提交的 form 表单时,就不得不对提交的手机号及验证码做基本的数据校验. 手写规则,非常浪费时间.使用 laravel 内置的 va ...
- Tesseract_ocr 字符识别基础及训练字库、合并字库
字符训练网上一搜一大堆,但作为一个初学者而言,字符合并网上却写的很笼统 首先,需要 生成的字符集.tif文件,位置文件 .box ,只要有这两个文件在,就可以合并字典(这个说的很有道理的样子) 好了, ...