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

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

Java原子变量

原子变量类基于CAS实现的, 当对共享变量进行read-modify-write更新操作时,通过原子变量类可以保障操作的原子性与可见性.对变量的read-modify-write更新操作是指当前操作不是一个简单的赋值,而是变量的新值依赖变量的旧值,如自增操作i++. 由于volatile只能保证可见性,无法保障原子性, 原子变量类内部就是借助一个Volatile变量,并且保障了该变量的read-modify-write操作的原子性, 有时把原子变量类看作增强的volatile变量. 原子变量类有12个,如:

               分组              原子变量类
基础数据型 AtomicInteger, AtomicLong, AtomicBoolean
数组型 AtomicIntegerArray, AtomicLongArray,AtomicReferenceArray
字段更新器 AtomicIntegerFieldUpdater, AtomicLongFieldUpdater, AtomicReferenceFieldUpdater
引用型 AtomicReference,AtomicStampedReference, AtomicMarkableReference

AtomicLong

package com.wkcto.atomics.atomiclong;

import java.util.concurrent.atomic.AtomicLong;

/**
 * 使用原子变量类定义一个计数器
 * 该计数器,在整个程序中都能使用,并且所有的地方都使用这一个计数器,这个计数器可以设计为单例
 * 老崔
 */
public class Indicator {
    //构造方法私有化
    private  Indicator(){}
    //定义一个私有的本类静态的对象
    private static  final  Indicator INSTANCE = new Indicator();
    //3)提供一个公共静态方法返回该类唯一实例
    public static  Indicator getInstance(){
        return INSTANCE;
    }

    //使用原子变量类保存请求总数,成功数,失败数
    private final AtomicLong requestCount = new AtomicLong(0);  //记录请求总数
    private final AtomicLong successCount = new AtomicLong(0);  //处理成功总数
    private final AtomicLong fialureCount = new AtomicLong(0);  //处理失败总数

    //有新的请求
    public void newRequestReceive(){
        requestCount.incrementAndGet();
    }
    //处理成功
    public void requestProcessSuccess(){
        successCount.incrementAndGet();
    }
    //处理失败
    public void  requestProcessFailure(){
        fialureCount.incrementAndGet();
    }

    //查看总数,成功数,失败数
    public long getRequestCount(){
        return requestCount.get();
    }
    public long getSuccessCount(){
        return successCount.get();
    }
    public long getFailureCount(){
        return fialureCount.get();
    }
}
复制代码
package com.wkcto.atomics.atomiclong;

import java.util.Random;

/**
 * 模拟服务器的请求总数, 处理成功数,处理失败数
 * 老崔
 */
public class Test {
    public static void main(String[] args) {
        //通过线程模拟请求,在实际应用中可以在ServletFilter中调用Indicator计数器的相关方法
        for (int i = 0; i < 10000; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    //每个线程就是一个请求,请求总数要加1
                    Indicator.getInstance().newRequestReceive();
                    int num = new Random().nextInt();
                    if ( num % 2 == 0 ){        //偶数模拟成功
                        Indicator.getInstance().requestProcessSuccess();
                    }else {     //处理失败
                        Indicator.getInstance().requestProcessFailure();
                    }
                }
            }).start();
        }

        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        //打印结果
        System.out.println( Indicator.getInstance().getRequestCount());     //总的请求数
        System.out.println( Indicator.getInstance().getSuccessCount());     //成功数
        System.out.println( Indicator.getInstance().getFailureCount());     //失败数
    }
}
复制代码

AtomicIntegerArray

原子更新数组

package com.wkcto.atomics.atomicarray;

import java.util.concurrent.atomic.AtomicIntegerArray;

/**
 * AtomicIntegerArray的基本操作
 * 原子更新数组
 * 老崔
 */
public class Test {
    public static void main(String[] args) {
        //1)创建一个指定长度的原子数组
        AtomicIntegerArray atomicIntegerArray = new AtomicIntegerArray(10);
        System.out.println( atomicIntegerArray );   //[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
        //2)返回指定位置的元素
        System.out.println( atomicIntegerArray.get(0));     //0
        System.out.println( atomicIntegerArray.get(1));     //0
        //3)设置指定位置的元素
        atomicIntegerArray.set(0, 10);
        //在设置数组元素的新值时, 同时返回数组元素的旧值
        System.out.println( atomicIntegerArray.getAndSet(1, 11) );  //0
        System.out.println( atomicIntegerArray );   //[10, 11, 0, 0, 0, 0, 0, 0, 0, 0]
        //4)修改数组元素的值,把数组元素加上某个值
        System.out.println( atomicIntegerArray.addAndGet(0, 22) );  //32
        System.out.println( atomicIntegerArray.getAndAdd(1, 33));   //11
        System.out.println( atomicIntegerArray );   //[32, 44, 0, 0, 0, 0, 0, 0, 0, 0]
        //5)CAS操作
        //如果数组中索引值为0的元素的值是32 , 就修改为222
        System.out.println( atomicIntegerArray.compareAndSet(0, 32, 222));  //true
        System.out.println( atomicIntegerArray );   //[222, 44, 0, 0, 0, 0, 0, 0, 0, 0]
        System.out.println( atomicIntegerArray.compareAndSet(1, 11, 333));  //false
        System.out.println(atomicIntegerArray);
        //6)自增/自减
        System.out.println( atomicIntegerArray.incrementAndGet(0) );    //223, 相当于前缀
        System.out.println( atomicIntegerArray.getAndIncrement(1));     //44, 相当于后缀
        System.out.println( atomicIntegerArray );   //[223, 45, 0, 0, 0, 0, 0, 0, 0, 0]
        System.out.println( atomicIntegerArray.decrementAndGet(2));     //-1
        System.out.println( atomicIntegerArray);    //[223, 45, -1, 0, 0, 0, 0, 0, 0, 0]
        System.out.println( atomicIntegerArray.getAndDecrement(3));     //0
        System.out.println( atomicIntegerArray );   //[223, 45, -1, -1, 0, 0, 0, 0, 0, 0]
    }
}
复制代码
package com.wkcto.atomics.atomicarray;

import java.util.concurrent.atomic.AtomicIntegerArray;

/**
 * 在多线程中使用AtomicIntegerArray原子数组
 * 老崔
 */
public class Test02 {
    //定义原子数组
    static AtomicIntegerArray atomicIntegerArray = new AtomicIntegerArray(10);

    public static void main(String[] args) {
        //定义线程数组
        Thread[] threads = new Thread[10];
        //给线程数组元素赋值
        for (int i = 0; i < threads.length; i++) {
            threads[i] = new AddThread();
        }
        //开启子线程
        for (Thread thread : threads) {
            thread.start();
        }
        //在主线程中查看自增完以后原子数组中的各个元素的值,在主线程中需要在所有子线程都执行完后再查看
        //把所有的子线程合并到当前主线程中
        for (Thread thread : threads) {
            try {
                thread.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println( atomicIntegerArray );
    }

    //定义一个线程类,在线程类中修改原子数组
    static class AddThread extends Thread{
        @Override
        public void run() {
            //把原子数组的每个元素自增1000次
            for (int j = 0; j < 100000; j++) {
                for (int i = 0; i < atomicIntegerArray.length(); i++) {
                    atomicIntegerArray.getAndIncrement(i % atomicIntegerArray.length());
                }
            }
           /* for (int i = 0; i < 10000; i++) {
                atomicIntegerArray.getAndIncrement(i % atomicIntegerArray.length());
            }*/
        }
    }
}
复制代码

猜你喜欢

转载自juejin.im/post/7019481809717035021