Java多线程学习「超详细总结」Java原子变量(下)

287 阅读1分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

AtomicIntegerFieldUpdater

AtomicIntegerFieldUpdater可以对原子整数字段进行更新,要求:\

● 字符必须使用volatile修饰,使线程之间可见。
● 只能是实例变量,不能是静态变量,也不能使用final修饰。

package com.wkcto.atomics.atominintegerfiled;

/**
 * 使用AtomicIntegerFieldUpdater更新的字段必须使用volatile修饰
 * 老崔
 */
public class User {
    int id;
    volatile  int age;

    public User(int id, int age) {
        this.id = id;
        this.age = age;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", age=" + age +
                '}';
    }
}
package com.wkcto.atomics.atominintegerfiled;

import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;

/**
 * 线程类,
 * 老崔
 */
public class SubThread extends Thread {
    private  User user;         //要更新的User对象
    //创建AtomicIntegerFieldUpdater更新器
    private AtomicIntegerFieldUpdater<User> updater = AtomicIntegerFieldUpdater.newUpdater(User.class, "age");

    public SubThread(User user) {
        this.user = user;
    }

    @Override
    public void run() {
        //在子线程中对user对象的age字段自增10次
        for (int i = 0; i < 10; i++) {
            System.out.println( updater.getAndIncrement(user));
        }
    }
}
package com.wkcto.atomics.atominintegerfiled;

/**
 * 老崔
 */
public class Test {
    public static void main(String[] args) {
        User user = new User(1234, 10);
        //开启10个线程
        for (int i = 0; i < 10; i++) {
            new SubThread(user).start();
        }

        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println( user );
    }
}

AtomicReference

可以原子读写一个对象

package com.wkcto.atomics.atomicreference;

import java.util.Random;
import java.util.concurrent.atomic.AtomicReference;

/**
 * 使用AtomicReference原子读写一个对象
 * 老崔
 */
public class Test01 {
    //创建一个AtomicReference对象
    static AtomicReference<String> atomicReference = new AtomicReference<>("abc");

    public static void main(String[] args) throws InterruptedException {
        //创建100个线程修改字符串
        for (int i = 0; i < 100; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        Thread.sleep(new Random().nextInt(20));
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    if (atomicReference.compareAndSet("abc","def")){
                        System.out.println(Thread.currentThread().getName() + "把字符串abc更改为def");
                    }
                }
            }).start();
        }
        //再创建100个线程
        for (int i = 0; i < 100; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        Thread.sleep(new Random().nextInt(20));
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    if (atomicReference.compareAndSet("def","abc")){
                        System.out.println(Thread.currentThread().getName() + "把字符串还原为abc");
                    }
                }
            }).start();
        }

        Thread.sleep(1000);
        System.out.println(atomicReference.get());
    }
}
package com.wkcto.atomics.atomicreference;

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

/**
 * 演示AtomicReference可能会出现CAS的ABA问题
 * 老崔
 */
public class Test02 {
    private static AtomicReference<String> atomicReference = new AtomicReference<>("abc");
    public static void main(String[] args) throws InterruptedException {
        //创建第一个线程,先把abc字符串改为"def",再把字符串还原为abc
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                atomicReference.compareAndSet("abc", "def");
                System.out.println(Thread.currentThread().getName() + "--" + atomicReference.get());
                atomicReference.compareAndSet("def", "abc");
            }
        });

        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println( atomicReference.compareAndSet("abc", "ghg"));
            }
        });
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        System.out.println( atomicReference.get());
    }
}
package com.wkcto.atomics.atomicreference;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.atomic.AtomicStampedReference;

/**
 * AtomicStampedReference原子类可以解决CAS中的ABA问题
 * 在AtomicStampedReference原子类中有一个整数标记值stamp, 每次执行CAS操作时,需要对比它的版本,即比较stamp的值
 * 老崔
 */
public class Test03 {
//    private static AtomicReference<String> atomicReference = new AtomicReference<>("abc");
    //定义AtomicStampedReference引用操作"abc"字符串,指定初始化版本号为0
    private static AtomicStampedReference<String> stampedReference = new AtomicStampedReference<>("abc", 0);
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                stampedReference.compareAndSet("abc", "def", stampedReference.getStamp(), stampedReference.getStamp()+1);
                System.out.println(Thread.currentThread().getName() + "--" +stampedReference.getReference());
                stampedReference.compareAndSet("def", "abc", stampedReference.getStamp(), stampedReference.getStamp()+1);
            }
        });
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                int stamp = stampedReference.getStamp();        //获得版本号
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println( stampedReference.compareAndSet("abc", "ggg", stamp, stamp+1));
            }
        });

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

        System.out.println( stampedReference.getReference() );
    }
}