原创

Java 中能创建 volatile 数组吗?

可以创建 volatile 数组,但是volatile只保证对数组的引用可见,而不是数组元素。 即如果是改变引用指向的数组,将受到volatile的保护;但是对多个线程同时改变数组里面的元素,volatile不能保证。

volatile 的作用

作为指令关键字,确保本条指令不会因编译器的优化而省略,且要求每次直接读值。

实现 volatile 数组 的两种方式

  1. 使用AtomicIntegerArray 或 AtomicLongArray
    AtomicIntegerArray类实现一个int数组,通过类的get()和set()方法可以使用volatile语义访问各个字段。
  2. 自定义实现,在每次字段写入后重写数组引用,比较麻烦(因为现在一次写入涉及两次写入)
    volatile int[] arrays = {1,1,1,1,1}

代码示例

package com.yueny.study.jdk.volatilex;

import java.util.Arrays;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author fengyang <deep_blue_yang@126.com>
 * @date 2020/9/28  2:58 下午
 * @title: VolatileArrays
 * @projectName algorithm
 * @description:
 */
public class VolatileArrays {
    // 不保证原子性
    static volatile int[] arrays = {1,1,1,1,1};
    // 不保证原子性
    static int x = 0;
    // 不保证原子性
    static volatile int y = 0;
    // 保证原子性
    static volatile AtomicInteger z = new AtomicInteger(0);

    private static ExecutorService executorService = Executors.newFixedThreadPool(5);

    /**
     * 模拟并发线程
     *
     * @param args
     */
    public static void main(String []args) {
        System.out.println("模拟操作前:");
        System.out.println(Arrays.toString(arrays));
        System.out.println("X:" + x);
        System.out.println("Y:" + y);
        System.out.println("Z:" + z);

        // 模拟 1000 个线程进行 arrays、x、y、z 的累加
        for (int i=0;i<10000;i++){
            executorService.submit(new ChangeNum());
        }

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

        System.out.println("模拟操作结束, 执行1000次,期望均为 1000。");
        System.out.println(Arrays.toString(arrays));
        System.out.println("X:" + x);
        System.out.println("Y:" + y);
        System.out.println("Z:" + z);
    }

    static class ChangeNum implements Runnable{
        @Override
        public void run() {
            /*
             * 数据全部各自加1
             */
            arrays[0]=arrays[0]+1;
            arrays[1]=arrays[1]+1;
            arrays[2]=arrays[2]+1;
            arrays[3]=arrays[3]+1;
            arrays[4]=arrays[4]+1;

            x=x+1;
            y=y+1;
            z.incrementAndGet();
        }
    }

}

结果

模拟操作前:
[1, 1, 1, 1, 1]
X:0
Y:0
Z:0
模拟操作结束, 执行1000次,期望均为 1000。
[9995, 9996, 9996, 9997, 9998]
X:9997
Y:9997
Z:10000
正文到此结束
广告是为了更好的提供数据服务
本文目录