java 线程数组_Java 数组线程间可见性问题

并发编程中通常使用 volatile 保证线程间可见性,但是被 volatile 修饰的数组中元素是无法保证线程间可见的,例如 ConcurrentHashMap 对这一问题采用 Unsafe 的方式访问 U.getObjectVolatile(tab, ((long)i << ASHIFT) + ABASE);

关于 volatile 示例

暂无关于 volatile array 失败测试用例

解释

在 Java 中无论是基础类型数组还是对象类型数组底层都是一个对象,区别是数组对象在对象头中多出 32 位数组长度标识。

普通对象需要保证线程间可见通常修饰 volatile 关键字,若对象内成员未修饰 volatile 关键字,成员是无法保证线程间可见的。在初始化数组或者创建数组是无法为元素修饰 volatile 关键字的,同样的解释还有:

这个是因为Java数组在元素层面的元数据设计上的缺失,无法表达元素是final、volatile等语义,所以开了后门,使用getObjectVolatile用来补上无法表达元素是volatile的坑,@Stable用来补上final的坑,数组元素就跟没有标volatile的成员字段一样,无法保证线程之间可见性。

链接:https://www.jianshu.com/p/5808db3e2ace

保证数组元素可见性的几种方式

Unsafe.getVolatileObject

public class VolatileArray {

private volatile Object[] nums = new Object[]{new Object()};

private static Unsafe U;

private static long NUMS;

static {

try {

Class> clazz = Class.forName("sun.misc.Unsafe");

Field theUnsafe = clazz.getDeclaredField("theUnsafe");

theUnsafe.setAccessible(true);

U = (Unsafe) theUnsafe.get(null);

NUMS = U.objectFieldOffset(VolatileArray.class.getDeclaredField("nums"));

} catch (ClassNotFoundException | NoSuchFieldException | IllegalAccessException e) {

e.printStackTrace();

}

}

public static void main(String[] args) throws InterruptedException {

VolatileArray example = new VolatileArray();

new Thread(() -> {

try {

TimeUnit.MILLISECONDS.sleep(200);

} catch (InterruptedException e) {

e.printStackTrace();

}

example.nums[0] = new Object();

}).start();

new Thread(() -> {

while (true) {

Object[] objects = (Object[]) U.getObjectVolatile(example, NUMS);

if (objects[0] != null) {

System.out.println("index updated");

break;

}

}

}).start();

}

}

AtomicReferenceArray

public class VolatileArray {

private AtomicReferenceArray atomicReferenceArray = new AtomicReferenceArray<>(1);

public static void main(String[] args) throws InterruptedException {

VolatileArray example = new VolatileArray();

new Thread(() -> {

try {

TimeUnit.MILLISECONDS.sleep(200);

} catch (InterruptedException e) {

e.printStackTrace();

}

example.atomicReferenceArray.set(0, new Object());

}).start();

new Thread(() -> {

while (true) {

if (example.atomicReferenceArray.get(0) != null) {

System.out.println("index updated");

break;

}

}

}).start();

}

}

AtomicReferenceArray 实现与上方 Unsafe 代码思想基本一致。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值