实现全局自增id最简单有效的方式是什么?java.util.concurrent.atomic包定义了一些常见类型的原子变量。这些原子变量为我们提供了一种操作单一变量无锁(lock-free)的线程安全(thread-safe)方式。实际上该包下面的类为我们提供了类似volatile变量的特性,同时还提供了诸如boolean compareAndSet(expectedValue, updateValue)的功能。不使用锁实现线程安全听起来似乎很不可思议,这其实是通过CPU的compare and swap指令实现的,由于硬件指令支持当然不需要加锁了。

先不去讨论这些细节,我们来看一下原子变量的用法。一个典型的用法是可以使用原子变量轻松实现全局自增id,就像下面这样:

// 线程安全的序列id生成器
class Sequencer {
private final AtomicLong sequenceNumber = new AtomicLong(0);
public long next() {
return sequenceNumber.getAndIncrement();
}
}

上述代码利用AtomicLong创建了一个Sequencer类,不断调用该类的next()方法就可以得到线程安全的自增id,用起来非常简单直观。下面我们给出每种原子变量类型的用法说明。

AtomicInteger and AtomicLong

AtomicIntegerAtomicLong分别代表原子类型的整型和长整型,这两个类提供十分相似的功能,仅仅是位宽不同。如上例所示,原子整型可用于多线程下全局自增id,除此之外还提供了原子比较-赋值等操作,诸如compareAndSet(expect, update)decrementAndGet()getAndDecrement()getAndSet(newValue)等等,更全面的接口描述可参考JDK文档。需要提醒的是这些函数都是通过原子CPU指令实现,执行效率较高。

原子整型看似跟普通整型(Integer, Long)类型相似,但不能使用原子整型替代普通整型,因为原子整型是可变的,而普通整型不可变。由于这个原因,使用原子整型作为Map的key并不是个好主意。

你可能会想当然的以为应该有AtomicFloatAtomicDouble,遗憾的是类库里并没有这两个类型,AtomicByteAtomicShort也没有。如果需要替代方案是使用AtomicIntegerAtomicLong。可通过Float.floatToRawIntBits(float)Float.intBitsToFloat(int)将Float存储到AtomicInteger中,类似的Double类型也可以存储到AtomicLong中。

AtomicReference

AtomicReference用于存放一个可以原子更新的对象引用。该类包含get(), set(), compareAndSet(), getAndSet()等原子方法来获取和更新其代表的对象引用。

AtomicXXXArray

atomic包下面有三种原子数组:AtomicIntegerArray, AtomicLongArra, AtomicReferenceArray,分别代表整型、长整型和引用类型的原子数组。原子数组使得我们可以线程安全的方式去修改和访问数组里的单个元素。简单示例如下:

// 原子数组示例
AtomicLongArray longArray = new AtomicLongArray(10);// 创建长度为10的原子数组
longArray.set(1, 100);
long v = longArray.getAndIncrement(1); AtomicReferenceArray<String> referenceArray = new AtomicReferenceArray<>(16);
referenceArray.set(3, "love");
referenceArray.compareAndSet(3, "love", "you");

简单来说原子数组就是一种支持线程安全的数组,仍然具有数组“定长”的性质,如果访问元素超过了数组的长度,将会抛出IndexOutOfBoundsException。你可能已经想到了,可以使用线程安全的容器来避免容量不足,我们会在后续章节介绍。

什么是线程安全?

线程安全是指多线程访问是时,无论线程的调度策略是什么,程序能够正确的执行。导致线程不安全的一个原因是状态不一致,如果线程A修改了某个共享变量(比如给id++),而线程B没有及时知道,就会导致B在错误的状态上执行,结果的正确性也就无法保证。原子变量为我们提供了一种保证单个状态一致的简单方式,一个线程修改了原子变量,另外的线程立即就能看到,这比通过锁实现的方式效率要高;如果要同时保证多个变量状态一致,就只能使用锁了。

本文地址

Java原子变量的更多相关文章

  1. 谈论Java原子变量和同步的效率 -- 颠覆你的生活

    我们认为,由于思维定式原子变量总是比同步运行的速度更快,我想是这样也已经,直到实现了ID在第一次测试过程生成器不具有在这样一个迷迷糊糊的东西. 测试代码: import java.util.Array ...

  2. Java原子变量类需要注意的问题

    在学习多线程时,遇到了原子变量类,它是基于 CAS 和 volatile 实现的,能够保障对共享变量进行 read-modify-write 更新操作的原子性和可见性.于是我就写了一段代码试试,自认为 ...

  3. 全面了解 Java 原子变量类

    目录   一.原子变量类简介  二.基本类型  三.引用类型  四.数组类型  五.属性更新器类型  参考资料

  4. 用Java原子变量的CAS方法实现一个自旋锁

    为了防止无良网站的爬虫抓取文章,特此标识,转载请注明文章出处.LaplaceDemon/ShiJiaqi. http://www.cnblogs.com/shijiaqi1066/p/5999610. ...

  5. Java并发之原子变量和原子引用与volatile

    我们知道在并发编程中,多个线程共享某个变量或者对象时,必须要进行同步.同步的包含两层作用:1)互斥访问(原子性):2)可见性:也就是多个线程对共享的变量互斥地访问,同时线程对共享变量的修改必须对其他线 ...

  6. java并发编程学习: 原子变量(CAS)

    先上一段代码: package test; public class Program { public static int i = 0; private static class Next exte ...

  7. 《Java并发编程实战》第十五章 原子变量与非堵塞同步机制 读书笔记

    一.锁的劣势 锁定后假设未释放.再次请求锁时会造成堵塞.多线程调度通常遇到堵塞会进行上下文切换,造成很多其它的开销. 在挂起与恢复线程等过程中存在着非常大的开销,而且通常存在着较长时间的中断. 锁可能 ...

  8. Java并发编程之原子变量

    原子变量最主要的一个特点就是所有的操作都是原子的,synchronized关键字也可以做到对变量的原子操作.只是synchronized的成本相对较高,需要获取锁对象,释放锁对象,如果不能获取到锁,还 ...

  9. Java多线程-----原子变量和CAS算法

       原子变量      原子变量保证了该变量的所有操作都是原子的,不会因为多线程的同时访问而导致脏数据的读取问题      Java给我们提供了以下几种原子类型: AtomicInteger和Ato ...

随机推荐

  1. Linux SVN安装部署

    系统:centos6.3 svn: subversion-1.6.1 apache: httpd-2.2.29 //创建svn路径 [root@localhost /]# mkdir svn [roo ...

  2. 了解 : angular ng-messages

    ng-messages="form['positionTitle' + languageVersion.typeEnum].$error ng-messages="form.pos ...

  3. 第27篇 重复造轮子---模拟IIS服务器

    在写程序的时候,重复造轮子是程序员的一个大忌,很多人对重复造轮子持有反对的态度,但是我觉得这个造轮子的过程,是对于现有的知识的一个深入的探索的过程,虽然我们不可能把轮子造的那么的完善,对于现在有的东西 ...

  4. 第20篇 js高级知识---深入原型链

    前面把js作用域和词法分析都说了下,今天把原型链说下,写这个文章费了点时间,因为这个东西有点抽象,想用语言表达出来不是很容易,我想写的文章不是简单的是官方的API的copy,而是对自己的知识探索和总结 ...

  5. cocoapods 删除已导入项目的第三方库和移除项目中的cocoapods

    第一部分将介绍如何删除项目中已经由cocoapods配置好的第三方 1.打开项目中的Podfile文件 2.删除选中的pod Snapkit的命令行3.打开终端cd到当前项目的根目录下重新执行pod ...

  6. How to build mscorlib.dll with visual studio

    Recently, Microsoft Corportation has released a new look for .NET Reference Source. And you may find ...

  7. OpenStack/devstack with Neutron on Ubuntu 14 (1)

    安装前,推荐安装一个全新的Ubuntu Server14.04,如果使用之前的ubuntu, 中间可能遇到各种的python包依赖,以及软件版本不对应的问题 环境准备,新建stack用户,给予sudo ...

  8. Mac下tomcat配置ssl

    最近在搞单点登录CAS,第一步就是需要给tomcat配置证书.但是,第一次配置就遇到了个问题排插了一下午.下面来存一份文档,以备以后遇到. 一.首先准备好环境 java环境:配置好环境变量,找到jdk ...

  9. Python实现Windows定时关机

    是最初的几个爬虫,让我认识了Python这个新朋友,虽然才刚认识了几天,但感觉有种莫名的默契感.每当在别的地方找不到思路,总能在Python找到解决的办法.自动关机,在平时下载大文件,以及跑程序的时候 ...

  10. Untiy文档总结(1)-Profiling

    这段时间上班了,不是什么大公司,虽说很闲但是不能断了学习,就开始看优化有关的文档,虽说自己英语渣的要死,但也要读下去,逼着自己翻译完了,里面有抄Unity圣典的,但自己是看Unity5.5文档写的,只 ...