原子类操作

  既然强调了并发访问,那么就必须考虑操作系统位数:32位操作系统还是64位操作系统,对于long型数据类型而言,是64位的。但是如果现在项目运行在32位系统上,则long型数据会占用32位空间进行数据的保存。

如果现在每一个程序类里面都去使用long类型,那么进行处理的时候都需要手动进行volatile配置,那样就太麻烦了。

为了解决这样的问题,在juc里面提供了一个atomic子包,这个子包里面保存的都是原子性的操作数据,也就是说里面包含的数据类型都使用volatile进行声明。

原子操作分类

原子操作:是指操作过程中不会被中断,保证数据操作是以原子方式进行的。

  • 基本数据类型:AtomicInteger, AtomicLong, AtomicBoolean
  • 数组类型:AtomicIntegerArray, AtomicLongArray, AtomicRefernceArray
  • 引用类型: AtomicReference, AtomicStampedRerence, AtomicMarkableReference
  • 对象的属性修改类型: AtomicIntegerFieldUpdater, AtomicLongFieldUpdater, AtomicReferenceFieldUpdater.

范例:观察“AtomicLong”类型

  实际上在使用“AtomicLong”的时候里面包含的就是“private volatile long value”.

  1. package so.strong.concurrents;
  2. import java.util.concurrent.atomic.AtomicLong;
  3. public class StrongDemo {
  4. public static void main(String[] args) throws Exception {
  5. AtomicLong num = new AtomicLong(10);
  6. System.out.println("数据自增:"+num.incrementAndGet());
  7. System.out.println("数据自减:"+num.decrementAndGet());
  8. }
  9. }

  如果要进行数据类型的基础数学运算也是需要通过方法进行的。

范例:实现基础数学运算

  1. package so.strong.concurrents;
  2. import java.util.concurrent.atomic.AtomicLong;
  3. public class StrongDemo {
  4. public static void main(String[] args) throws Exception {
  5. AtomicLong num = new AtomicLong(100);
  6. System.out.println("加法操作:"+num.addAndGet(10));
  7. System.out.println("减法操作:"+num.addAndGet(-9));
  8. }
  9. }

  毕竟这种操作不是原始的基本数据类型,它的操作时刻需要保证数据在多线程访问下的并发安全性。

对于原子性的处理,以上并不是它的重点,只是它的操作形式,这里面有一个最为重要的方法,CAS方法:

  1. public final boolean compareAndSet(long expect, long update) {
  2. return unsafe.compareAndSwapLong(this, valueOffset, expect, update);
  3. }

范例:观察CAS方法的使用

  1. package so.strong.concurrents;
  2. import java.util.concurrent.atomic.AtomicLong;
  3. public class StrongDemo {
  4. public static void main(String[] args) throws Exception {
  5. AtomicLong num = new AtomicLong(100); //设置原子性操作
  6. //如果现在要进行修改的内容是100,即:原始的原子类型里面为100,则使用300替换num的内容
  7. System.out.println(num.compareAndSet(101,300)); //比较的值等于100,返回true
  8. System.out.println(num);
  9. }
  10. }

使用CAS方法进行内容修改的时候一定要设置一个原始的比较内容,如果内容相同才可以修改,如果现在操作的是数组也有与之对应的程序类AtomicLongArray。

AtomicLongArray有两个构造方法:

  • 动态开辟:设置数组的长度

    1. public AtomicLongArray(int length) {
    2. array = new long[length];
    3. }
  • 静态开辟:设置具体的数组内容
    1. public AtomicLongArray(long[] array) {
    2. this.array = array.clone();
    3. }

范例:进行数组操作

  1. package so.strong.concurrents;
  2. import java.util.concurrent.atomic.AtomicLongArray;
  3. public class StrongDemo {
  4. public static void main(String[] args) throws Exception {
  5. AtomicLongArray array = new AtomicLongArray(new long[]{1,2,3});
  6. array.set(0,99); //原子性的数组必须使用set修改内容
  7. System.out.println(array);
  8. }
  9. }

  除了对long类型进行原子性的处理支持之外也可以对引用类型(对象)进行原子性操作。

范例:使用原子性进行对象的描述

  1. package so.strong.concurrents;
  2. import java.util.concurrent.atomic.AtomicReference;
  3. public class StrongDemo {
  4. public static void main(String[] args) throws Exception {
  5. AtomicReference<Member> ref = new AtomicReference<>();
  6. Member memA = new Member("张三", 22);
  7. Member memB = new Member("李四", 32);
  8. ref.set(memA);
  9. ref.compareAndSet(memA, memB); //对象引用变更只得依靠地址比较“==”
  10. System.out.println(ref);
  11. }
  12. }
  13.  
  14. class Member {
  15. private String name;
  16. private int age;
  17. public Member(String name, int age) {
  18. this.name = name;
  19. this.age = age;
  20. }
  21.  
  22. @Override
  23. public String toString() {
  24. return "name= " + this.name + ",age= " + this.age;
  25. }
  26. }

以上的几种类型严格来讲都算是常用的几种处理形式,但是在Java开发里面有可能会遇见一种很奇怪的问题,即:可能本身类中定义的类型不是AtomicLong,那么可以利用AtomicLongFieldUpdater类来完成。

  1. public abstract class AtomicLongFieldUpdater<T>
  2. // 抽象类AtomicLongFieldUpdater更新器
  1. AtomicLongFieldUpdater更新器获得对象的方法:
  1. @CallerSensitive
  2. public static <U> AtomicLongFieldUpdater<U> newUpdater(Class<U> tclass, String fieldName) {
  3. Class<?> caller = Reflection.getCallerClass();
  4. if (AtomicLong.VM_SUPPORTS_LONG_CAS)
  5. return new CASUpdater<U>(tclass, fieldName, caller);
  6. else
  7. return new LockedUpdater<U>(tclass, fieldName, caller);
  8. }

范例:使用AtomicLongFieldUpdater更新器

  1. package so.strong.concurrents;
  2. import java.util.concurrent.atomic.AtomicLongFieldUpdater;
  3. public class StrongDemo {
  4. public static void main(String[] args) throws Exception {
  5. Book book = new Book(100001,"Java从入门到放弃");
  6. book.setBid(200002); //修改bid
  7. System.out.println(book);
  8. }
  9. }
  10.  
  11. class Book {
  12. private volatile long bid; //必须追加volatile关键字
  13. private String title;
  14. public Book(long bid, String title) {
  15. this.bid = bid;
  16. this.title = title;
  17. }
  18.  
  19. @SuppressWarnings({"rawtypes","unchecked"})
  20. public void setBid(long bid) {
  21. AtomicLongFieldUpdater updater = AtomicLongFieldUpdater.newUpdater(super.getClass(), "bid");
  22. updater.compareAndSet(this, this.bid, bid);//使用CAS方法进行内容的修改
  23. }
  24.  
  25. @Override
  26. public String toString() {
  27. return "图书编号: " + this.bid + ", 名称: " + this.title;
  28. }
  29. }

并发访问中为了保证多位的数据类型的完整性一定要使用volatile关键字,同时在整个juc的开包里面会发现有大量的原子操作类出现。

JUC——原子类操作(三)的更多相关文章

  1. java 多线程系列---JUC原子类(三)之AtomicLongArray原子类

    AtomicLongArray介绍和函数列表 在"Java多线程系列--“JUC原子类”02之 AtomicLong原子类"中介绍过,AtomicLong是作用是对长整形进行原子操 ...

  2. Java多线程系列--“JUC原子类”02之 AtomicLong原子类

    概要 AtomicInteger, AtomicLong和AtomicBoolean这3个基本类型的原子类的原理和用法相似.本章以AtomicLong对基本类型的原子类进行介绍.内容包括:Atomic ...

  3. Java多线程系列--“JUC原子类”04之 AtomicReference原子类

    概要 本章对AtomicReference引用类型的原子类进行介绍.内容包括:AtomicReference介绍和函数列表AtomicReference源码分析(基于JDK1.7.0_40)Atomi ...

  4. Java多线程系列--“JUC原子类”05之 AtomicLongFieldUpdater原子类

    概要 AtomicIntegerFieldUpdater, AtomicLongFieldUpdater和AtomicReferenceFieldUpdater这3个修改类的成员的原子类型的原理和用法 ...

  5. 【Java_多线程并发编程】JUC原子类——4种原子类

    根据修改的数据类型,可以将JUC包中的原子操作类可以分为4种,分别是: 1. 基本类型: AtomicInteger, AtomicLong, AtomicBoolean ;2. 数组类型: Atom ...

  6. java多线程系类:JUC原子类:03之AtomicLongArray原子类

    概要 AtomicIntegerArray, AtomicLongArray, AtomicReferenceArray这3个数组类型的原子类的原理和用法相似.本章以AtomicLongArray对数 ...

  7. Java多线程系列--“JUC原子类”03之 AtomicLongArray原子类

    概要 AtomicIntegerArray, AtomicLongArray, AtomicReferenceArray这3个数组类型的原子类的原理和用法相似.本章以AtomicLongArray对数 ...

  8. JDK原子类操作

    JDK原子类操作及原理 在JDK5之后,JDK提供了对变量的原子类操作, java.util.concurrent.atomic里都是原子类 原子类的分类 原子更新基本类型 原子更新数组 原子更新抽象 ...

  9. 【Java_多线程并发编程】JUC原子类——原子类中的volatile变量和CAS函数

    JUC中的原子类是依靠volatile变量和Unsafe类中的CAS函数实现的. 1. volatile变量的特性 内存可见性(当一个线程修改volatile变量的值后,另一个线程就可以实时看到此变量 ...

随机推荐

  1. Sublime插件WakaTime使用

    1.安装WakaTime插件 ctrl+shift+p-->输入pi-->回车-->输入wakaTime-->回车(进行安装) 安装好后会显示输入api key的输入栏 (也可 ...

  2. (转)查看mysql数据库连接数、并发数相关信息

    查看mysql数据库连接数.并发数相关信息 1.mysql> show status like 'Threads%';+-------------------+-------+| Variabl ...

  3. 【Javascript-基础-getOwnPropertyNames】Object.getOwnPropertyNames() 获取对象自身可枚举属性

    可枚举属性和不可枚举属性 在JavaScript中,对象的属性分为可枚举和不可枚举之分,它们是由属性的enumerable值决定的.可枚举性决定了这个属性能否被for-in查找遍历到. 可枚举属性 e ...

  4. Linux-- 文件编辑器 vi/vim(2)

    多文件编辑 vi 可以用来打开多个文件,如下: 进入编辑界面以后,输入 :n 可以切换到下一个文本,:N 可以切换到上一个文本,:files 列出目前这个 vi 打开的所有文件,举例如下: 切换到下一 ...

  5. Python-常见错误梳理

    1. takes exactly 1 argument (2 given) 出现此错误一般是在某对象调用类的某方法时出现.因为在python中某类的实例对象调用方法时,是首先将自身作为一个参数传入此方 ...

  6. 转:介绍几个著名的实用的Java反编译工具,提供下载

    from :http://www.glorze.com/219.html 反编译 众所周知,我们将源代码进行编译,生成可执行的程序或者容器发布包,这个将代码转换的过程就是编译的过程,而反编译就是将这些 ...

  7. ABAP术语-ABAP 术语发布结束

    ABAP 术语发布结束 原文:http://www.cnblogs.com/qiangsheng/archive/2008/03/21/1116236.html 经历了大约三个月,终于把 BC417 ...

  8. Redis开启远程访问及密码认证

    配置 redis.conf 文件 [root@localhost bin]# vi /usr/local/redis/bin/redis.conf 将 bind 127.0.0.1 注释掉 将 pro ...

  9. HCNA(一)网络传输介质

    一 .同轴线缆 介绍:同轴线缆是一种早期的网络传输介质,同轴电缆的得名与它的结构相关,由内导体.外导体.绝缘介质和防护套四部分组成.同样支持10Mbps传输速率.现在已经基本被淘汰,不在应用于企业网络 ...

  10. Python系列之 迭代器和生成器

    很多Python的程序员都会混淆 迭代器 和 生成器 的概念和作用,分不清到底两个有什么区别.今天我们来好好说一说这两个概念. 迭代器(Iterator) Iterator Pattern Itera ...