• Java并发编程之原子操作类


    什么是原子操作类
    当更新一个变量的时候,多出现数据争用的时候可能出现所意想不到的情况。这时的一般策略是使用synchronized解决,因为synchronized能够保证多个线程不会同时更新该变量。然而,从jdk 5之后,提供了粒度更细、量级更轻,并且在多核处理器具有高性能的原子操作类。因为原子操作类把竞争的范围缩小到单个变量上,这可以算是粒度最细的情况了。

    原子操作类相当于泛化的volatile变量,能够支持原子读取-修改-写操作。比如AtomicInteger表示一个int类型的数值,提供了get和set方法,这些volatile类型的变量在读取与写入上有着相同的内存语义。原子操作类共有13个类,在java.util.concurrent.atomic包下,可以分为四种类型的原子更新类:原子更新基本类型、原子更新数组类型、原子更新引用和原子更新属性。

    下面介绍这各种原子操作类
    1 原子更新基本类型:使用原子方式更新基本类型

    AtomicBoolean:原子更新布尔变量
    AtomicInteger:原子更新整型变量
    AtomicLong:原子更新长整型变量
    2 原子更新数组:通过原子更新数组里的某个元素

    AtomicIntegerArray:原子更新整型数组的某个元素
    AtomicLongArray:原子更新长整型数组的某个元素
    AtomicReferenceArray:原子更新引用类型数组的某个元素
    3 原子更新引用类型:更新引用类型

    AtomicReference:原子更新引用类型
    AtomicReferenceFieldUpdater:原子更新引用类型里的字段
    AtomicMarkableReference:原子更新带有标记位的引用类型
    4 原子更新字段:原子更新某个类的某个字段

    AtomicIntegerFieldUpdater:原子更新整型字段
    AtomicLongFieldUpdater:原子更新长整型字段
    AtomicStampedReference:原子更新带有版本号的引用类型
    我们接下来会通过对AtomicInteger的讲解来深入认识原子操作类
    在单线程环境下,执行num++等操作时不会出现问题,那么,在多线程环境下是否还是跟单线程环境下一样安全呢?我们通过一段代码进行模拟。

    public class Demo {

    private static int num = 0;

    public static void add() {
    num++;
    }

    public static void main(String[] args) {
    Thread[] myThread = new Thread[10];
    for(Thread thread : myThread) {
    thread = new Thread() {
    @Override
    public void run() {
    for(int i = 0;i < 1000;i++) {
    add();
    }
    }
    };
    thread.start();
    }

    while (Thread.activeCount() > 1) {
    Thread.yield();
    }
    System.out.println(num);
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    我们进行三次测试,得出结果分别是

    8400
    8318
    9856

    在没有同步条件下,自增操作不具备原子性,在多线程环境下是不安全的。

    既然我们上面的方法不安全,那该咋办呢,总不能坐以待毙吧?没事,我们有一件新武器,那就是AtomicInteger原子类型。把上面的代码改为使用AtomicInteger,让我们看看接下来会发生什么?

    import java.util.concurrent.atomic.AtomicInteger;

    public class Demo {

    public static AtomicInteger num = new AtomicInteger(0);

    public static void add() {
    num.incrementAndGet();
    }

    public static void main(String[] args) {
    Thread[] myThread = new Thread[10];
    for(Thread thread : myThread) {
    thread = new Thread() {
    @Override
    public void run() {
    for(int i = 0;i < 1000;i++) {
    add();
    }
    }
    };
    thread.start();
    }

    while (Thread.activeCount() > 1) {
    Thread.yield();
    }
    System.out.println(num);
    }
    }
    ---------------------

  • 相关阅读:
    关于php中,记录日志中,将数组转为json信息记录日志时遇到的问题总结
    快速搭建vsftp 服务器并配置指定目录
    Chrome 里的请求报错 "CAUTION: Provisional headers are shown" 是什么意思?
    使用sed,grep 批量修改文件内容
    Linux如何让进程在后台运行的三种方法详解
    redis 安装方式
    beanstalk 安装
    mysql 错误信息
    PostgreSQL LIMIT 子句
    pg_dump和pg-server版本不一致问题的解决办法
  • 原文地址:https://www.cnblogs.com/hyhy904/p/10930603.html
Copyright © 2020-2023  润新知