十、Atomic和ABA问题

1、原子类AtomicInteger的API讲解

package day05.part1;

import java.util.concurrent.atomic.AtomicInteger;

/**
 * 原子类AtomicInteger的API讲解
 * @author xzq
 */
public class AtomicTest01 {

    public static void main(String[] args) {
        /*
         *空参数 默认为0
         */
        AtomicInteger atmInteger=new AtomicInteger();
        /*
         * 注意下面的API都是线程不安全的,只用于初始化使用
         * 在多线程共享数据时不要使用
         */
        System.out.println("获取值:"+atmInteger.get());
        atmInteger=new AtomicInteger(5);
        System.out.println("获取值:"+atmInteger.get());
        atmInteger.set(10);
        System.out.println("获取值:"+atmInteger.get());

        /*
         * 以下方法能保证多线程情况下的原子性
         */
      int getAndAddResult = atmInteger.getAndAdd(10);//a=a+10
      System.out.println("自增后的返回值:"+getAndAddResult);
      System.out.println("当前类中的值:"+atmInteger.get());

        //没有提供自减指定值的方法所以用这样的方式实现自减
      atmInteger.getAndAdd(-5);//a=a-5
      atmInteger.decrementAndGet();//a--
        /*
         * 原子赋值操作,必须传当前最新读到的预期值,
         * 且必须为int类型
         */
      atmInteger.compareAndSet(14, 20);//当前值是14 如果下面判断也是14 就会被更新为20
     /* atmInteger.compareAndSet(15, 20);
      atmInteger.compareAndSet(10, 20);*/
        System.out.println("当前类中的值:"+atmInteger);


    }

}

十、Atomic和ABA问题

2、原子类AtomicBoolean的API讲解

package day05.part1;

import java.util.concurrent.atomic.AtomicBoolean;

/**
 * 原子类AtomicBoolean的API讲解
 * @author xzq
 */
public class AtomicTest02 {

    public static void main(String[] args) {

        AtomicBoolean atmBoolean=new AtomicBoolean();
        /*
         * 注意下面的API都是线程不安全的,只用于初始化使用
         * 在多线程共享数据时不要使用
         * 不赋值默认是false
         */
        atmBoolean.set(true);


        //要赋值的时候用这个API,可以保证本赋值操作的原子性
//      atmBoolean.getAndSet(true);
        /*
         * 和AtomicInteger一样,必须传一个预期的值,如果预期的值
         * 和当前类中的值不同(就是在赋值过程中有被其它线程打断更改的情况)
         * 那么就不进行赋值操作,保留原值。
         */
        atmBoolean.compareAndSet(true, true);

        System.out.println("当前类中的值:"+atmBoolean);


    }

}

十、Atomic和ABA问题

3、原子类AtomicLong的API讲解

package day05.part1;

import java.util.concurrent.atomic.AtomicLong;

/**
 * 原子类AtomicLong的API讲解
 * CPU有32位的,也有64位的,
 * 32位的CPU代表依编指令一次可以处理32  bit(位)的数据 4个字节
 * 64位的CPU代表汇编指令一次可以处理64  bit(位)的数据 8个字节
 *
 * int     是等于4byte(4个字节)=  32位
 * long  是等于8byte(8个字节)=64位
 * 如果是32位的CPU,那么处理long型的数据是先读高位,再读低位分两次读取
 * 为了保证2次读取的原子性,那么就在AtomicLong中加了一个对32位CPU的支持
 * @author xzq
 */
public class AtomicTest03 {

    public static void main(String[] args) {

        AtomicLong atmLong=new AtomicLong();
        /*
         * 注意下面的API都是线程不安全的,只用于初始化使用
         * 在多线程共享数据时不要使用
         */
        atmLong.set(30L);


        //要赋值的时候用这个API,可以保证本赋值操作的原子性
        atmLong.getAndSet(35L);
        /*
         * 和AtomicInteger一样,必须传一个预期的值,如果预期的值
         * 和当前类中的值不同(就是在赋值过程中有被其它线程打断更改的情况)
         * 那么就不进行赋值操作,保留原值。
         */
        atmLong.compareAndSet(31L, 36L);
//      atmLong.compareAndSet(30L, 35L);

        System.out.println("当前类中的值:"+atmLong);

    }

}

十、Atomic和ABA问题

4、原子类AtomicReference的API讲解

package day05.part1;

import day05.bean.Person;

import java.util.concurrent.atomic.AtomicReference;

/**
 * 原子类AtomicReference的API讲解
 * @author xzq
 */
public class AtomicTest04 {

    public static void main(String[] args) {

        AtomicReference<Person> atmRef=new AtomicReference<>();
        /*
         * 注意下面的API都是线程不安全的,只用于初始化使用
         * 在多线程共享数据时不要在线程内部去使用
         */
        Person p=new Person("Peter",115,"北京");
        /*
         * 对于没有重写hashCode的类的实例那么它的hashCode就是它的引用地址
         * 这里用int数组为例,证明对象的引用是用一个int型的变量来存储的
         */
        int[]  arr=new int[10];
        int refInt= arr.hashCode();
        System.out.println("数组对象的引用是:"+arr);
        System.out.println("数组对象的引用,用int类型表示为:"+refInt);
        atmRef.set(p);


        //要赋值的时候用这个API,可以保证本赋值操作的原子性
      Person toUpdateP = new Person("Cat", 38, "北京");
      atmRef.getAndSet(toUpdateP);
        /*
         * 和AtomicInteger一样,必须传一个预期的值,如果预期的值
         * 和当前类中的值不同(就是在赋值过程中有被其它线程打断更改的情况)
         * 那么就不进行赋值操作,保留原值。
         * 对比的是应用 而不是对象内容
         */
      boolean casIsSuccess = atmRef.compareAndSet(new Person("Cat", 38, "杭州"), toUpdateP);
     // boolean casIsSuccess = atmRef.compareAndSet(p, toUpdateP);

//      System.out.println("CAS操作是否成功:"+casIsSuccess);
        System.out.println("当前类中的值:"+atmRef);



        /*
         * 如果要实现原子写操作,那么自己手写一个原子类
         * 我已经写好了,请看MyAtomicReference
         */

    }

}

十、Atomic和ABA问题
5、ABA问题

package day05.part1;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.LockSupport;

/**
 * ABA问题
 * @author xzq
 */
public class AtomicTest05 {


    public static void main(String[] args) {
        final AtomicInteger atmInteger=new AtomicInteger(1);


        new Thread("线程1:"){
            @Override
            public void run() {
                String threadName = Thread.currentThread().getName();
                //这里读到的是1
                int getValue = atmInteger.get();
                System.out.println(threadName+"读到的数据是:"+getValue);
                //在进行CAS算法的原子操作之前阻塞1秒方便其它线程进行打断后操作
                LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(1));
                //进行CAS算法的原子操作将1  ---->2
                if(atmInteger.compareAndSet(getValue, 5)){
                    System.out.println(threadName+"把:"+getValue+"更新为   5成功!");
                }else{
                    System.out.println(threadName+"更新操作失败!");
                }
            }

        }.start();


        new Thread("线程2:"){

            @Override
            public void run() {
                String threadName = Thread.currentThread().getName();
                //这里读到的是1
                int getValue = atmInteger.get();
                System.out.println(threadName+"读到的数据是:"+getValue);
                //进行CAS算法的原子操作将1  ---->2
                if(atmInteger.compareAndSet(getValue, 2)){
                    System.out.println(threadName+"把:"+getValue+"更新为   2");
                    getValue= atmInteger.get();
                    System.out.println(threadName+"读到的数据是:"+getValue);
                    //进行CAS算法的原子操作将2  ---->1
                    if(atmInteger.compareAndSet(getValue, 1)){
                        System.out.println(threadName+"把:"+getValue+"更新为   1成功!");
                    }
                }
            }

        }.start();

    }

}

十、Atomic和ABA问题
6、解决ABA问题1

package day05.part1;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicStampedReference;
import java.util.concurrent.locks.LockSupport;

/**
 * 解决ABA问题
 * @author xzq
 */
public class AtomicTest06_1 {

    public static void main(String[] args) {

        final AtomicStampedReference<Integer> atmStaRef=new AtomicStampedReference<Integer>(1, 0);

        new Thread("线程1:"){

            @Override
            public void run() {
                String threadName = Thread.currentThread().getName();
                //这里读到的是1
                int getValue = atmStaRef.getReference();
                int stamp = atmStaRef.getStamp();
                System.out.println(threadName+"读到的数据是:"+getValue+",版本号是:"+stamp);
                //在进行CAS算法的原子操作之前阻塞1秒方便其它线程进行打断后操作
                LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(1));
                if(atmStaRef.compareAndSet(getValue, 2, stamp, stamp+1)){
                    System.out.println(threadName+"把:"+getValue+"更新为   5成功!");
                }else{
                    System.out.println(threadName+"更新操作失败!");
                }
            }

        }.start();


        new Thread("线程2:"){

            @Override
            public void run() {
                String threadName = Thread.currentThread().getName();
                //这里读到的是1
                int getValue = atmStaRef.getReference();
                int stamp = atmStaRef.getStamp();
                System.out.println(threadName+"读到的数据是:"+getValue);
                //进行CAS算法的原子操作将1  ---->2
                if(atmStaRef.compareAndSet(getValue, 2,stamp,stamp+1)){
                    System.out.println(threadName+"把:"+getValue+"更新为   2");
                    getValue= atmStaRef.getReference();
                    System.out.println(threadName+"读到的数据是:"+getValue);
                    //进行CAS算法的原子操作将2  ---->1
                    if(atmStaRef.compareAndSet(getValue, 1,stamp,stamp+1)){
                        System.out.println(threadName+"把:"+getValue+"更新为   1成功!");
                    }
                }
            }

        }.start();

    }

}

十、Atomic和ABA问题
6、解决ABA问题2

package day05.part1;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicMarkableReference;
import java.util.concurrent.locks.LockSupport;

/**
 * 解决ABA问题
 * @author xzq
 */
public class AtomicTest06_2 {

    public static void main(String[] args) {

        final AtomicMarkableReference<Integer> atmMarRef=new AtomicMarkableReference<Integer>(1, false);
        new Thread("线程1:"){

            @Override
            public void run() {
                String threadName = Thread.currentThread().getName();
                //这里读到的是1
                int getValue = atmMarRef.getReference();
                boolean marked = atmMarRef.isMarked();
                System.out.println(threadName+"读到的数据是:"+getValue+",标记是:"+marked);
                //在进行CAS算法的原子操作之前阻塞1秒方便其它线程进行打断后操作
                LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(1));
                if(atmMarRef.compareAndSet(getValue, 2, marked, true)){
                    System.out.println(threadName+"把:"+getValue+"更新为   5成功!");
                }else{
                    System.out.println(threadName+"更新操作失败!");
                }
            }

        }.start();


        new Thread("线程2:"){

            @Override
            public void run() {
                String threadName = Thread.currentThread().getName();
                //这里读到的是1
                int getValue = atmMarRef.getReference();
                boolean marked = atmMarRef.isMarked();
                System.out.println(threadName+"读到的数据是:"+getValue+",标记是:"+marked);
                //进行CAS算法的原子操作将1  ---->2
                if(atmMarRef.compareAndSet(getValue, 2,marked,!marked)&&atmMarRef.attemptMark(2, marked)){
                    System.out.println(threadName+"把:"+getValue+"更新为   2");
                    //重置marked


                    getValue= atmMarRef.getReference();
                    marked=atmMarRef.isMarked();
                    System.out.println(threadName+"读到的数据是:"+getValue);
                    //进行CAS算法的原子操作将2  ---->1
                    if(atmMarRef.compareAndSet(getValue, 1,marked,!marked)){
                        System.out.println(threadName+"把:"+getValue+"更新为   1成功!");
                    }
                }
            }

        }.start();

    }

}

十、Atomic和ABA问题
7、解决ABA问题 原子类AtomicStampedReference的API讲解

package day05.part1;

import java.util.concurrent.atomic.AtomicStampedReference;

/**
 * 解决ABA问题 原子类AtomicStampedReference的API讲解
 *
 * @author xzq
 */
public class AtomicTest07 {

    public static void main(String[] args) {
        AtomicStampedReference<Integer> atmStaRef = new AtomicStampedReference<Integer>(40, 0);
        int stamp = atmStaRef.getStamp();
        boolean casIsSuccess = atmStaRef.compareAndSet(40, 41, stamp, stamp + 1);
//      boolean casIsSuccess =atmStaRef.compareAndSet(40, 41,1 , stamp+1);

        System.out.println("CAS操作是否成功:"+casIsSuccess);
        System.out.println("当前类中的值:" + atmStaRef.getReference());

    }

}

十、Atomic和ABA问题
8、解决ABA问题 原子类AtomicMarkableReference的API讲解

package day05.part1;

import java.util.concurrent.atomic.AtomicMarkableReference;

/**
 * 解决ABA问题 原子类AtomicMarkableReference的API讲解
 *
 * @author xzq
 */
public class AtomicTest08 {

    public static void main(String[] args) {
        AtomicMarkableReference<Integer>  atmMarRef=new AtomicMarkableReference<Integer>(50, false);
        boolean marked = atmMarRef.isMarked();
        boolean casIsSuccess = atmMarRef.compareAndSet(50, 51, marked, !marked);
//      boolean casIsSuccess = atmMarRef.compareAndSet(50, 51, true, !marked);

        System.out.println("CAS操作是否成功:"+casIsSuccess);
        System.out.println("当前类中的值:" + atmMarRef.getReference());

    }

}

十、Atomic和ABA问题
9、原子类AtomicIntegerArray、AtomicLongArray和 AtomicReferenceArray的API讲解

package day05.part1;

import java.util.concurrent.atomic.AtomicIntegerArray;
import java.util.concurrent.atomic.AtomicLongArray;
import java.util.concurrent.atomic.AtomicReferenceArray;

/**
 * 原子类AtomicIntegerArray、AtomicLongArray和
 * AtomicReferenceArray的API讲解
 *
 * @author xzq
 */
public class AtomicTest09 {

    public static void main(String[] args) {

//      AtomicIntegerArray  atmIntArr=new AtomicIntegerArray(5);
        AtomicIntegerArray atmIntArr=new AtomicIntegerArray(new int[]{1,2,3,4,5});
        AtomicLongArray atmLongArr=new AtomicLongArray(6);
        AtomicReferenceArray<String> atmRefArr=new AtomicReferenceArray<>(7);
//      atmIntArr.set(0, 11);
//      atmIntArr.getAndSet(0, 12);
        /*
         * 传入一个期望值,如果当前读到的值和预期值一样就更新
         * 不一样就什么也不做
         * 1是下标为1的数字  如果为2 修改为12
         */
        boolean casIsSuccess = atmIntArr.compareAndSet(1, 2, 12);
//      boolean casIsSuccess = atmIntArr.compareAndSet(1, 22, 12);

        //-------------AtomicIntegerArray的打印
        System.out.println("整型数组长度为:"+atmIntArr.length());
        System.out.println("整型数组第1个元素为:"+atmIntArr.get(0));
        System.out.println("整型数组第2个元素为:"+atmIntArr.get(1));

        //-------------AtomicLongArray的打印
        atmLongArr.getAndSet(5, 6);
        System.out.println("长整型数组长度为:"+atmLongArr.length());
        System.out.println("长整型第1个元素为:"+atmLongArr.get(0));
        System.out.println("长整型第6个元素为:"+atmLongArr.get(5));


        //-------------AtomicReferenceArray的打印
        atmRefArr.getAndSet(6, "Peter");
        System.out.println("引用类型数组长度为:"+atmRefArr.length());
        System.out.println("引用类型第1个元素为:"+atmRefArr.get(0));
        System.out.println("引用类型第7个元素为:"+atmRefArr.get(6));

        System.out.println("CAS操作是否成功:"+casIsSuccess);
//      System.out.println("当前类中的值:" + atmMarRef.getReference());

    }

}

十、Atomic和ABA问题

上一篇:java-redis排行榜value+time排序


下一篇:【转】压力测试的几个道理