重温java知识(三十九、JUC并发编程之三:原子操作类)

在多线程操作中经常会出现多个线程对一个共享变量的并发修改,为了保证此操作的正确性,最初的时候可以通过synchronized关键字操作。JDK1.5之后,可以通过java.util.concurrent.atomic包中的原子操作类来操作。
此包中提供的原子操作类可以分为4类:

  • 基本类型:AtomicInteger、 AtomicLong、 AtomicBoolean。
  • 数组类型:AtomicIntegerArray、AtomicLongArray、AtomicReferenceArray。
  • 引用类型:AtomicReference、AtomicStampedReference【带有引用版本号的】、 AtomicMarkableReference【标记节点】。
  • 对象的属性修改类型:AtomicIntegerFieldFupdater、 AtomicLongFieldUpdater、AtomicReferenceFieldUpdater。

原子操作类最大的特点是可以进行线程安全更新,即帮助用户使用一种更为简单的共享数据的线程同步处理操作,所以通过源代码,我们可以发现,在这些原子类数据保存属性上都使用类volatile关键字进行声明,这样就可以防止由于数据缓存所造成的数据更新不一致的问题。

1-1、【基本类型】使用AtomicLong进行原子性操作的例子:

package com.mydemo;

import java.util.concurrent.atomic.AtomicLong;

public class JUCDemo {

    public static void main(String[] args) {

        // 实例化原子操作类
        AtomicLong atomicLong = new AtomicLong(100l);

        // 增加数据并取得
        atomicLong.addAndGet(200);

        // 先获取而后再自增
        long current = atomicLong.getAndIncrement();

        // 自增前的内容
        System.out.println(current);

        // 自增后的内容
        System.out.println(atomicLong.get());
    }
}

运行结果:
300
301

1-2、【基本类型】利用多线程操作的例子:

package com.mydemo;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;

public class JUCDemo {

    public static void main(String[] args) {
        // 实例化原子操作类
        AtomicLong atomicLong = new AtomicLong(100);
        for (int i = 0; i < 10; i++) {
            new Thread(
                    () -> {
                        // 增加数据并取得
                        atomicLong.addAndGet(200);
                    }
            ).start();
        }
        // 休眠2秒,等待执行结果
        try {
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        // 自增后的内容
        System.out.println(atomicLong.get());
    }
}

运行结果:
2100 

1-3、【基本类型】判断并设置新内容的例子:

package com.mydemo;

import java.util.concurrent.atomic.AtomicLong;

public class JUCDemo {

    public static void main(String[] args) {

        // 实例化原子操作类
        AtomicLong atomicLong = new AtomicLong(100l);

        // 内容相同,返回true
        System.out.println(atomicLong.compareAndSet(100l, 300l));

        // 取出数据
        System.out.println(atomicLong.get());
    }
}

运行结果:
true
300

2-1、【数组类型】使用AtomicReferenceArray类操作的例子:

package com.mydemo;

import java.util.concurrent.atomic.AtomicReferenceArray;

public class JUCDemo {

    public static void main(String[] args) {
        String infos[] = new String[]{
                "www.baidu.com",
                "www.google.com",
                "www.alibaba.com"
        };
        AtomicReferenceArray<String> atomicReferenceArray = new AtomicReferenceArray<>(infos);
        /**
         * 在使用compareAndSet()方法进行比较时,是通过“==”方式实现的比较操作
         *
         * 原因:
         * 由底层C语言实现的。
         * 该类操作是基于地址指针的形式处理的,所以只允许通过“==”进行地址判断
         */
        System.out.println(atomicReferenceArray.compareAndSet(0, "www.baidu123.com", "www.test.com"));
        System.out.println(atomicReferenceArray.compareAndSet(1, "www.google.com", "www.test.com"));
        // 输出
        System.out.println(atomicReferenceArray.get(0));
        System.out.println(atomicReferenceArray.get(1));
    }
}

运行结果:
false
true
www.baidu.com
www.test.com

3-1、【引用类型】使用AtomicReference类操作引用数据的例子:

package com.mydemo;

import java.util.concurrent.atomic.AtomicReference;

public class JUCDemo {

    public static void main(String[] args) {

        // 实例化Member实例
        Member memberA = new Member("张三", 18);
        Member memberB = new Member("李四", 20);

        AtomicReference<Member> atomicReference = new AtomicReference<>(memberA);

        // 修改当前保存数据
        atomicReference.compareAndSet(memberA, memberB);

        // 输出当前数据内容
        System.out.println(atomicReference);
    }
}

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 "Member{" +
                "姓名:'" + name + '\'' +
                ", 年龄:" + age +
                '}';
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

运行结果:
Member{姓名:'李四', 年龄:20}

3-2、【引用类型】使用AtomicStampedReference类进行引用原子性操作的例子:

package com.mydemo;

import java.util.concurrent.atomic.AtomicStampedReference;

public class JUCDemo {

    public static void main(String[] args) {

        // 实例化Member实例
        Member memberA = new Member("张三", 18);
        Member memberB = new Member("李四", 20);

        // 由于AtomicStampedReference需要提供版本号,所以在初始化时定义版本号为1
        AtomicStampedReference<Member> atomicStampedReference =
                new AtomicStampedReference<>(memberA, 1);

        // 在进行CAS操作时除了要设置替换内容外,
        // 也需要设置正确的版本号,否则无法替换。
        atomicStampedReference.compareAndSet(memberA, memberB, 1, 2);

        // 输出当前数据内容
        System.out.println(atomicStampedReference.getReference());

        // 获取版本号
        System.out.println(atomicStampedReference.getStamp());
    }
}

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 "Member{" +
                "姓名:'" + name + '\'' +
                ", 年龄:" + age +
                '}';
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

运行结果:
Member{姓名:'李四', 年龄:20}
2

3-3、【引用类型】使用AtomicMarkableReference类进行标记原子性操作的例子:

package com.mydemo;

import java.util.concurrent.atomic.AtomicMarkableReference;

public class JUCDemo {

    public static void main(String[] args) {

        // 实例化Member实例
        Member memberA = new Member("张三", 18);
        Member memberB = new Member("李四", 20);

        // 由于AtomicMarkableReference需要提供标记位才可以进行判断
        AtomicMarkableReference<Member> atomicMarkableReference =
                new AtomicMarkableReference<>(memberA, true);

        // 在进行CAS操作时除了要设置替换内容外,
        // 也需要设置标记号,否则无法替换。
        atomicMarkableReference.compareAndSet(memberA, memberB, true, false);

        // 输出当前数据内容
        System.out.println(atomicMarkableReference.getReference());
    }
}

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 "Member{" +
                "姓名:'" + name + '\'' +
                ", 年龄:" + age +
                '}';
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

运行结果:
Member{姓名:'李四', 年龄:20}

4-1、【对象的属性修改类型】实现属性操作的例子:

package com.mydemo;

import java.util.concurrent.atomic.AtomicLongFieldUpdater;

public class JUCDemo {

    public static void main(String[] args) {

        Book book = new Book(1001, "java从入门到放弃");
        book.setId(2003);
        System.out.println(book);
    }
}

class Book {

    /**
     * 必须使用volatile定义
     * 否则将会出现IllegalArgumentException异常
     */
//    private long id;
    private volatile long id;
    private String title;

    public Book(long id, String title) {
        this.id = id;
        this.title = title;
    }

    @Override
    public String toString() {
        return "Book{" +
                "id:" + id +
                ", 名称:'" + title + '\'' +
                '}';
    }

    public long getId() {
        return id;
    }

    public void setId(long id) {
//        this.id = id;
        AtomicLongFieldUpdater<Book> atomicLongFieldUpdater =
                AtomicLongFieldUpdater.newUpdater(Book.class, "id");
        atomicLongFieldUpdater.compareAndSet(this, this.id, id);
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }
}

运行结果:
Book{id:2003, 名称:'java从入门到放弃'}

4-2、【对象的属性修改类型】并发计算的例子:

package com.mydemo;

import java.util.concurrent.atomic.DoubleAccumulator;

public class JUCDemo {

    public static void main(String[] args) {

        /**
         * 原子性的累加器只适合于进行基础的数据统计,
         * 并不适用于其他更加细粒度的操作。
         */

        // 累加器
        DoubleAccumulator doubleAccumulator = new DoubleAccumulator(
                (x, y) -> x + y, 1.1
        );

        // 原始内容
        System.out.println(doubleAccumulator.doubleValue());

        // 加法计算
        doubleAccumulator.accumulate(20);

        // 获取数据
        System.out.println(doubleAccumulator.get());

    }
}

运行结果:
1.1
21.1

4-3、【对象的属性修改类型】使用加法器计算的例子:

package com.mydemo;

import java.util.concurrent.atomic.DoubleAdder;

public class JUCDemo {

    public static void main(String[] args) {

        // 定义加法器
        DoubleAdder doubleAdder = new DoubleAdder();

        // 数据执行加法
        doubleAdder.add(10);
        doubleAdder.add(20);
        doubleAdder.add(30);

        // 数据累加
        System.out.println(doubleAdder.sum());
    }
}

运行结果:
60.0
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值