(转)利用CAS算法实现通用线程安全状态机
在多线程环境下,如果某个类是有状态的,那我们在使用前,需要保证所有该类的实例对象状态一致,否则会出现意向不到的bug。下面是通用线程安全状态机的实现方法。
public class ThreadSaveState{
private int x;
private int y;
private enum State {NEW, INITIALIZING, INITIALIZED};
private final AtomicReference<State> init = new AtomicReference<State>(State.NEW);
public ThreadSaveState() {
};
public ThreadSaveState(int x, int y) {
initialize(x, y);
}
private void initialize(int x, int y) {
if (!init.compareAndSet(State.NEW, State.INITIALIZING)) {
throw new IllegalStateException("Already initialized");
}
this.x = x;
this.y = y;
//… Do anything else the original constructor did
init.set(State.INITIALIZED);
}
//所有公共接口,都要先调用该方法检测对象完整性
private void checkInit() {
if (init.get() != State.INITIALIZED) {
throw new IllegalStateException("Uninitialized");
}
}
//示例公用接口
public int getX() {
checkInit();
return x;
}
//示例公用接口
public int getY() {
checkInit();
return y;
}
}
这种模式利用compareAndSet方法来操作枚举的原子引用,关于compareAndSet方法,其内部是CAS算法,即:Compare and Swap, 翻译成比较并交换,源码如下:
java.util.concurrent包中借助CAS实现了区别于synchronouse同步锁的一种乐观锁,使用这些类在多核CPU的机器上会有比较好的性能.
结合compareAndSet源码我们看下:
/**
* Atomically sets the value to the given updated value
* if the current value {@code ==} the expected value.
* @param expect the expected value
* @param update the new value
* @return true if successful. False return indicates that
* the actual value was not equal to the expected value.
*/
public final boolean compareAndSet(V expect, V update) {
return unsafe.compareAndSwapObject(this, valueOffset, expect, update);
}
根据注释,CAS有3个操作数,内存值V,旧的预期值A,要修改的新值B。当且仅当预期值A和内存值V相同时,将内存值V修改为B,返回True,否则返回false。
再看看我们初始化的代码:
if (!init.compareAndSet(State.NEW, State.INITIALIZING)) {
throw new IllegalStateException("Already initialized");
}
只有当state是New的时候,才开始初始化,否则直接报错。这就保证了对象的完整性,因为如果没有这样的防范机制,万一有个线程要在某个实例上调用initialize(),而另一个线程又要企图使用这个实例,第二个线程就有可能看到这个实例处于不一致的状态。
转载:http://blog.csdn.net/qq_27258799
(转)利用CAS算法实现通用线程安全状态机的更多相关文章
- 利用双重检查锁定和CAS算法:解决并发下数据库的一致性问题
背景 最近有一个场景遇到了数据库的并发问题.现在先由我来抽象一下,去掉不必要的繁杂业务. 数据库表book存储着每本书的阅读量,一开始数据库是空的,不存在任何的数据.当用户访问接口的时候,判断 ...
- (一)juc线程高级特性——volatile / CAS算法 / ConcurrentHashMap
1. volatile 关键字与内存可见性 原文地址: https://www.cnblogs.com/zjfjava/category/979088.html 内存可见性(Memory Visibi ...
- Java多线程系列——原子类的实现(CAS算法)
1.什么是CAS? CAS:Compare and Swap,即比较再交换. jdk5增加了并发包java.util.concurrent.*,其下面的类使用CAS算法实现了区别于synchronou ...
- 并发策略-CAS算法
对于并发控制而言,我们平时用的锁(synchronized,Lock)是一种悲观的策略.它总是假设每一次临界区操作会产生冲突,因此,必须对每次操作都小心翼翼.如果多个线程同时访问临界区资源,就宁可牺牲 ...
- Compare and Swap [CAS] 算法
一个Java 5中最好的补充是对原子操作的支持类,如AtomicInteger,AtomicLong等.这些类帮助你减少复杂的(不必要的)多线程代码,实际上只是完成一些基本操作,如增加或减少多个线程之 ...
- 三、原子变量与CAS算法
原子变量:jdk1.5 后 java.util.concurrent.atomic 包下提供了常用的原子变量: - AtomicBoolean - AtomicInteger - AtomicLong ...
- 原子变量与CAS算法(二)
一.锁机制存在的问题 (1)在多线程竞争下,加锁.释放锁会导致比较多的上下文切换和调度延时,引起性能问题. (2)一个线程持有锁会导致其它所有需要此锁的线程挂起. (3)如果一个优先级高的线程等待一个 ...
- 原子性 CAS算法
一. i++ 的原子性问题 1.问题的引入: i++ 的实际操作分为三个步骤:读--改--写 实现线程,代码如下: public class AtomicDemo implements Runnabl ...
- java CAS算法
CAS算法是硬件对于并发操作的支持,其中包含了三个操作数:内存值,预估值和更新值.没当要执行更新操作时,会先在同步方法中比较内存值和预估值是否相等,如果相等才会用更新值替换内存值,否则什么也不做. p ...
随机推荐
- 修改终端terminal
修改终端路径 显示的颜色 (1)在home目录中,新建 .dircolors: $vi .dircolors 输入下面内容 DIR 00;36 保存退出. (2)在 .bashrc文件中 $vi .b ...
- Lesnoe Ozero 2016. BSUIR Open 2016 Finals
A. Street magic 数位DP,设$f[i][j][k]$表示从低到高考虑$x$的后$i$位,$x$和$m$大小关系为$j$,和$n$大小关系为$k$的方案数. #include<cs ...
- srand rand
#include <stdlib.h> srand( (time(0)); rand()%100;
- Git服务器安装详解及安装遇到问题解决方案
git是一个不错的版本管理的工具.现在自己在搞一个简单的应用程序开发,想使用git来进行管理.在Google了配置文档后,还是受了N多的挫折.某些文档质量不高,浪费了好多时间...... 好,切入正题 ...
- BOM 浏览器对象模型_Storage 接口 - window.sessionStorage - window.localStorage
Storage 接口 用于脚本在浏览器保存数据. 保存的数据都以“键值对”的形式存在.也就是说,每一项数据都有一个键名和对应的值. 所有的数据都是以文本格式保存 受同域限制 ---- 某个网页存入的数 ...
- scrapy入门使用
scrapy入门 创建一个scrapy项目 scrapy startporject mySpider 生产一个爬虫 scrapy genspider itcast "itcast.cn&qu ...
- oralce 将浮点型字段,转为指定精度 并且四舍五入
使用 Round() 函数,该函数有两个参数,第一个参数: 将要转换的字段,第二个参数:保留的小数点位数 1 代表保留1位 2 代表保留2位 例子: SELECT round(123.446,1) ...
- Linux下Python模式下【Tab】自动补全
注:此文为转载他人博客,如有侵权,请联系我删除 1.我们需要一个tab补全的功能脚本 #!/usr/bin/python # python tab file import sys import re ...
- nodejs----微信注册测试号获取token
var PORT=8081; //监听8080端口号 var http=require('http'); var qs=require('qs'); var TOKEN='yezhenxu'; //必 ...
- Jumpserver之安装在CentOS主机步骤
环境 系统CentOS7.5 IP:172.16.90.248 关闭防火墙设置selinux systemctl stop firewalld setenforce 0 sed -i "s/ ...