大家碰到了实现一个线程安全的计数器的需求改怎么做呢?根据经验你应该知道我们要在多线程中实现共享变量的原子性和可见性问题,于是锁成为一个不可避免的话题,下文讨论的是与之对应的无锁CAS。

为什么要无锁

我们一想到在多线程下保证安全的方式,肯定是锁,不管从硬件、操作系统层面都或多或少在使用锁。锁有优缺点吗?

使用锁就需要获得锁、释放锁,CPU需要通过上下文切换和调度管理来进行这个操作,对于一个独占锁,一个线程在持有锁后没有执行结束,其他线程就必须等待,等到前面的线程执行完毕,CPU就会把锁拿出来给其他线程来抢了。锁的这种概念基于一种悲观机制,它总是认为数据会被修改,所以,你在操作一部分代码块之前先加一把锁,操作完成后再释放,这样就安全了。

什么是 CAS

比较并交换(compare and swap,CAS),是原子操作的一种,可用于在多线程编程中实现不被打断的数据交换操作,从而避免多线程同时改写某一数据时由于执行顺序不确定性以及中断的不可预知性产生的数据不一致性问题。该操作通过将内存中的值与指定的数据进行比较,当数值一样时,将内存中的数据替换成新值。

JAVA如何实现

package com.concurrent.program;

import java.util.ArrayList;

import java.util.Arrays;

import java.util.List;

import java.util.concurrent.atomic.AtomicInteger;

public class Counter {

private AtomicInteger atomicI = new AtomicInteger(0);

private int i = 0;

public static void main(String[] args) {

final Counter cas = new Counter();

Listts = new ArrayList(10);

long start = System.currentTimeMillis();

for (int j=0;j < 100; j++){

Thread t = new Thread(new Runnable() {

@Override

public void run() {

for (int i=0;i<10000; i++){

cas.count();

cas.safeCount();

}

}

});

ts.add(t);

}

for (Thread t : ts) {

t.start();

}

//等待所有线程执行完成

for (Thread t:ts){

try {

t.join();

} catch (InterruptedException e){

e.printStackTrace();

}

}

System.out.println(cas.i);

System.out.println(cas.atomicI.get());

System.out.println(System.currentTimeMillis() - start);

}

/**

* 使用CAS实现线程安全计数器

*/

private void safeCount(){

for(;;){

int i = atomicI.get();

boolean suc = atomicI.compareAndSet(i, ++i);

if (suc) {

break;

}

}

}

/**

* 非线程安全计数器

*/

private void count(){

i++;

}

}

以上代码实现了一个基于CAS线程安全的计数器方法safeCount和一个非线程安全的计数器方法count,读者可以自行运行,运行结果如下:

非线程安全计数器: 971850

使用CAS实现线程安全计数器: 1000000

执行时间:78ms

CAS存在的问题

1.ABA问题。因为CAS需要在操作值的时候,检查值有没有发生变化,如果没有则更新。但是如果原来一个值是A,变成了B,又变成A,那么使用CAS进行检查时会发现它的值没有发生变化,但是实际发生了变化了。ABA解决问题的思路就是使用版本号。在变量前面追加版本号,每次变量更新的时候把版本号加1,那么A→B→A就会变成1A→2B→3A。从JAVA1.5开始,JDK的Atomic包里提供了一个类AtomicStampedReference来解决ABA问题。

2.循环时间长,开销大。CAS长时间不成功,会给CPU带来非常大的执行开销。如果JVM能支持处理器提供的pause指令,那么效率会有一定的提示。

3.只能保证一个共享变量的原子操作。对多个共享变量操作时,CAS可以把多个共享变量合并成一个共享变量来操作。比如,有两个共享变量i=2,j=a,合并成ij=2a,然后用CAS来操作ij。从JAVA1.5开始,JDK的Atomic包里面提供了一个类AtomicReference类来保证引用对象之间的原子性,就可以把多个变量放在一个对象里面来进行CAS操作。

java 自旋方法_JAVA循环使用CAS实现自旋操作相关推荐

  1. java item方法_Java常用方法

    第一章 字符串 1 . 获取字符串的长度: length() 2 . 判断字符串的前缀或后缀与已知字符串是否相同 前缀 startsWith(String s) .后缀 endsWith(String ...

  2. java 获取方法_Java 反射理解(三)-- Java获取方法信息

    Java 反射理解(三)-- Java获取方法信息 基本的数据类型.void关键字,都存在类类型. 举例如下: public class ClassDemo2 { public static void ...

  3. java clone方法_Java Calendar clone()方法与示例

    java clone方法 日历类clone()方法 (Calendar Class clone() method) clone() method is available in java.util p ...

  4. java void方法_Java对象类的最终void wait(long ms)方法,包含示例

    java void方法 对象类最终无效等待(长毫秒) (Object Class final void wait(long ms)) This method is available in java. ...

  5. java tostring方法_Java虚拟机如执行方法调用的(二)?

    虚方法调用 Java里所有非私有实例方法调用都会被编译成invokevirtual指令. 接口方法调用都会被编译成invokeinterface指令.这两种指令都属于Java虚方法的调用. 在大多数情 ...

  6. java peek方法_Java ArrayDeque peek()方法与示例

    java peek方法 ArrayDeque类peek()方法 (ArrayDeque Class peek() method) peek() Method is available in java. ...

  7. java double方法_Java Double类compare()方法与示例

    java double方法 双类compare()方法 (Double class compare() method) compare() method is available in java.la ...

  8. java 析构方法_java析构方法详解

    之前给大家介绍了一下java构造方法,那么下面要给大家讲到的就是java析构方法,下面一起通过文章来了解一下吧. 析构方法和构造方法不同,真好是相反的,在对象脱离其作用域的时候,系统自动执行析构方法. ...

  9. java run 方法_java线程中的run()方法能有几个啊?

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 给个例子 package test; public class Test{ public static void main(String[] args){ ...

最新文章

  1. IPv6下CDN和网络的最佳实践
  2. django 如何提升性能(高并发)
  3. HDU1176(DP)
  4. android 单机斗地主,单机斗地主
  5. php beast linux安装,windows centos php-beast 安装
  6. web加减乘除法c#_C#的加减乘除的问题
  7. 学习笔记(06):MySQL数据库运维与管理-01-用户创建及授权
  8. stm32F4修改时钟频率,更换为8MHz晶振
  9. 敏捷开发“松结对编程”实践之二:计划与设计篇(大型研发团队,学习型团队,139团队,师徒制度,设计评审,预想陈述,共同估算,扑克牌估算)...
  10. 根据某个字段判断是否添加条件
  11. linux jdk路径
  12. 二次元始,跌宕几年,至学术略有成就并步入业界的我与NLP的这七年时光!
  13. linux下rsync服务的搭建
  14. php收费视频网站实现,超好影视网站PHP源码,一键采集视频资源,对接第三方免签码支付,能设置每个视频能否收费...
  15. 图像处理之图像分割(一)之活动轮廓模型:Snake算法简单梳理
  16. 实现音视频编解码工具 MediaCodec 创建解码器
  17. python已停止工作请关闭该程序_解决PyCharm的Python.exe已经停止工作的问题
  18. Mint-ui MessageBox.confirm 确定和取消事件
  19. iOS和Android的app界面设计规范
  20. 视频字幕文件 SSA、ASS 参数-攻略

热门文章

  1. Android中已经添加权限,依然提示缺少权限,此时你需要添加动态权限
  2. Spring的PropertyPlaceholderConfigurer应用
  3. php源码自动识别文本中的链接,自动加载识别文件Auto.php
  4. bootstrap五星评分_如何用纯代码实现评分星级显示?
  5. [转载] java给对象中的包装类设置默认值
  6. Python | 如何使用pip升级所有Python软件包?
  7. olap 多维分析_OLAP(在线分析处理)| OLAP多维数据集和操作
  8. php新闻删除功能设计,php原生开发新闻站之删除新闻
  9. 计算机专业技能高考试题素材,计算机技能高考模拟试题
  10. JVM(三)对象的生死判定和算法详解