文档章节

JUC——原子类操作(三)

o
 osc_z1hvg4cu
发布于 2018/04/24 17:05
字数 1168
阅读 10
收藏 0

精选30+云产品,助力企业轻松上云!>>>

原子类操作

  既然强调了并发访问,那么就必须考虑操作系统位数: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”.

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

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

 

范例:实现基础数学运算

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

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

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

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

 

范例:观察CAS方法的使用

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

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

AtomicLongArray有两个构造方法:

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

     

范例:进行数组操作

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

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

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

package so.strong.concurrents;
import java.util.concurrent.atomic.AtomicReference;
public class StrongDemo {
    public static void main(String[] args) throws Exception {
        AtomicReference<Member> ref = new AtomicReference<>();
        Member memA = new Member("张三", 22);
        Member memB = new Member("李四", 32);
        ref.set(memA);
        ref.compareAndSet(memA, memB); //对象引用变更只得依靠地址比较“==”
        System.out.println(ref);
    }
}

class Member {
    private String name;
    private int age;
    public Member(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "name= " + this.name + ",age= " + this.age;
    }
}

 

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

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

 

范例:使用AtomicLongFieldUpdater更新器

package so.strong.concurrents;
import java.util.concurrent.atomic.AtomicLongFieldUpdater;
public class StrongDemo {
    public static void main(String[] args) throws Exception {
        Book book = new Book(100001,"Java从入门到放弃");
        book.setBid(200002); //修改bid
        System.out.println(book);
    }
}

class Book {
    private volatile long bid; //必须追加volatile关键字
    private String title;
    public Book(long bid, String title) {
        this.bid = bid;
        this.title = title;
    }

    @SuppressWarnings({"rawtypes","unchecked"})
    public void setBid(long bid) {
        AtomicLongFieldUpdater updater = AtomicLongFieldUpdater.newUpdater(super.getClass(), "bid");
        updater.compareAndSet(this, this.bid, bid);//使用CAS方法进行内容的修改
    }

    @Override
    public String toString() {
        return "图书编号: " + this.bid + ", 名称: " + this.title;
    }
}

 

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

 

o
粉丝 0
博文 500
码字总数 0
作品 0
私信 提问
加载中
请先登录后再评论。

暂无文章

SnailSVN Pro for mac(SVN客户端) v1.9.9

macw为您带来SnailSVN Pro for mac ,SnailSVN Mac版是一款类似于 TortoiseSVN 的 Apache Subversion(SVN)客户端,与 Finder 紧密集成。SnailSVN Mac版允许你从 Finder 的上下文菜单中快速...

单手绕月
21分钟前
7
0
python网络编程(进程与多线程)

multiprocessing模块   由于GIL的存在,python中的多线程其实并不是真正的多线程,如果想要充分地使用多核CPU的资源,在python中大部分情况需要使用多进程。   multiprocessing包是Pytho...

osc_ky74f26k
21分钟前
5
0
CentOS7 redis5.0高可用部署

概述 Redis Sentinel为Redis提供高可用性。Redis Sentinel是一个分布式系统,Sentinel本身设计为在有多个Sentinel进程协同合作的配置中运行。具有多个Sentinel进程进行协作的优点如下: 1、当...

紅顏為君笑
21分钟前
6
0
Ocelot简易教程(四)之请求聚合以及服务发现

上篇文章给大家讲解了Ocelot的一些特性并对路由进行了详细的介绍,今天呢就大家一起来学习下Ocelot的请求聚合以及服务发现功能。希望能对大家有所帮助。 作者:依乐祝 原文地址:https://www...

osc_zo0djpuu
22分钟前
8
0
leetcode63(不同路径 II)--Java语言实现

求: 一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为“Finish”)。 现在...

拓拔北海
22分钟前
15
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部