Java并发编程札记-(三)JUC原子类-04原子方式更新引用

An object reference that may be updated atomically.

The AtomicReference class provides reference objects that may be read and written atomically, so when multiple threads try to reach them at the same time, only one will be able to do so.
提供了引用变量的读写原子性操作。

提供了如下的方法:

  • compareAndSet(V expect, V update):Atomically sets the value to the given updated value if the current value == the expected value.
  • getAndSet(V newValue):Atomically sets to the given value and returns the old value.
  • lazySet(V newValue):Eventually sets to the given value.
  • set(V newValue):Sets to the given value.
  • get():Gets the current value.

假设有一个类 Person,定义如下:

class Person {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = 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;
    }

    public String toString() {
        return "[name: " + this.name + ", age: " + this.age + "]";
    }
}

如果使用普通的对象引用,在多线程情况下进行对象的更新可能会导致不一致性。例如:

  1. 一个对象的初始状态为 name=Tom, age = 18。
  2. 在 线程1 中将 name 修改为 Tom1,age + 1。
  3. 在 线程2 中将 name 修改为 Tom2,age + 2。

我们认为只会产生两种结果:

  • 若 线程1 先执行,线程2 后执行,则中间状态为 name=Tom1, age = 19,结果状态为 name=Tom2, age = 21
  • 若 线程2 先执行,线程1 后执行,则中间状态为 name=Tom2, age = 20,结果状态为 name=Tom1, age = 21

但是可能的输出如下:

Person is [name: Tom, age: 18]
Thread2 Values [name: Tom1, age: 21]
Thread1 Values [name: Tom1, age: 21]
Now Person is [name: Tom1, age: 21]
// 普通引用
private static Person person;

public static void main(String[] args) throws InterruptedException {
    person = new Person("Tom", 18);

    System.out.println("Person is " + person.toString());

    Thread t1 = new Thread(new Task1());
    Thread t2 = new Thread(new Task2());

    t1.start();
    t2.start();

    t1.join();
    t2.join();

    System.out.println("Now Person is " + person.toString());
}

static class Task1 implements Runnable {
    public void run() {
        person.setAge(person.getAge() + 1);
        person.setName("Tom1");

        System.out.println("Thread1 Values "
                + person.toString());
    }
}

static class Task2 implements Runnable {
    public void run() {
        person.setAge(person.getAge() + 2);
        person.setName("Tom2");

        System.out.println("Thread2 Values "
                + person.toString());
    }
}

如果使用原子性对象引用,在多线程情况下进行对象的更新可以确保一致性。例如:

// 普通引用
private static Person person;
// 原子性引用
private static AtomicReference<Person> aRperson;

public static void main(String[] args) throws InterruptedException {
    person = new Person("Tom", 18);
    aRperson = new AtomicReference<Person>(person);

    System.out.println("Atomic Person is " + aRperson.get().toString());

    Thread t1 = new Thread(new Task1());
    Thread t2 = new Thread(new Task2());

    t1.start();
    t2.start();

    t1.join();
    t2.join();

    System.out.println("Now Atomic Person is " + aRperson.get().toString());
}

static class Task1 implements Runnable {
    public void run() {
        aRperson.getAndSet(new Person("Tom1", aRperson.get().getAge() + 1));

        System.out.println("Thread1 Atomic References "
                + aRperson.get().toString());
    }
}

static class Task2 implements Runnable {
    public void run() {
        aRperson.getAndSet(new Person("Tom2", aRperson.get().getAge() + 2));

        System.out.println("Thread2 Atomic References "
                + aRperson.get().toString());
    }
}

但是可能的输出如下:

Atomic Person is [name: Tom, age: 18]
Thread1 Atomic References [name: Tom1, age: 19]
Thread2 Atomic References [name: Tom2, age: 21]
Now Atomic Person is [name: Tom2, age: 21]

作者:专职跑龙套
链接:http://www.jianshu.com/p/882d0e2c3ea6
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值