java volatile 死锁_java生产者消费者引发的volatile关键字疑惑?

从另一个角度来看,Java内存模型是基于happens-before的。而你这里关于size的写入跟读取之间没有happens-before关系,那么很可能就读取不到最新的。而获取和释放一个锁之间具有happens-before关系,所以你把这个判断语句放到synchronized(Object.class)里面的话,应该也解决了这问题啦?

其实这里不加volatile应该也有另一种办法,题主能不能把文本代码发给我,我试试·····

=====================

感谢私信:).

首先我是从底层来看待这个问题(x86 cpu),你某个线程往一个变量里写入内容size++,那么只要你的写入操作本身是原子操作(cmpxchg,xadd,xchg),或者你的写入操作之后跟着一个原子操作(你这里的情况就是这样,size++后面有个释放锁的操作本身就是原子操作):

synchronized (Object.class) {

queue.add("a");

size++;

System.out.println("put " + queue.size());

}

那么这个size内存地址指代的内容,对于其他cpu就是可见的了。当然我们这里讨论的是线程,那么也就是说在操作系统的协调下,这个size内存地址指代的内容对于其他线程就是可见的了。但是为什么你的代码中还是没读到更新呢?我个人认为答案是Java内存模型的实现或者编译器的实现导致的。

所以站在解决这个问题的角度来看,我们并不需要把size生命为volatile变量,而只需要告诉编译器不要做多余的事,老老实实去读取那个size地址对应的变量,这里是我的方案:

import java.lang.reflect.Field;

import java.util.LinkedList;

import java.util.Queue;

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

import sun.misc.Unsafe;

public class Demo4 {

private static Queue queue = new LinkedList();

private static int size = 0;//声明成volatile不会死锁private static final int MAX = 10;

public static void main(String[] args) {

ExecutorService pool = Executors.newCachedThreadPool();

pool.execute(new Runnable() {

@Override

public void run() {

while (true) {

_unsafe.loadFence();

if (size < MAX) {

synchronized (Object.class) {

queue.add("a");

size++;

System.out.println("put " + queue.size());

}

}

}

}

});

pool.execute(new Runnable() {

@Override

public void run() {

while (true) {

_unsafe.loadFence();

if (size > 0) {

synchronized (Object.class) {

queue.poll();

size--;

System.out.println("get " + queue.size());

}

}

}

}

});

}

private static final Unsafe _unsafe = UtilUnsafe.getUnsafe();

private static class UtilUnsafe {

private UtilUnsafe() {

}

public static Unsafe getUnsafe() {

if (UtilUnsafe.class.getClassLoader() == null)

return Unsafe.getUnsafe();

try {

final Field fld = Unsafe.class.getDeclaredField("theUnsafe");

fld.setAccessible(true);

return (Unsafe) fld.get(UtilUnsafe.class);

} catch (Exception e) {

throw new RuntimeException("Could not obtain access to sun.misc.Unsafe", e);

}

}

}

}

这里的_unsafe.loadFence()会确保下面读取的size是更新过的。

或者你也可以值针对size变量,

import java.lang.reflect.Field;

import java.util.LinkedList;

import java.util.Queue;

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

import sun.misc.Unsafe;

public class Demo4 {

private static Queue queue = new LinkedList();

private static int size = 0;//声明成volatile不会死锁private static final Object size_base;

private static final long size_offset;

private static final int MAX = 10;

public static void main(String[] args) {

ExecutorService pool = Executors.newCachedThreadPool();

pool.execute(new Runnable() {

@Override

public void run() {

while (true) {

if (_unsafe.getIntVolatile(size_base, size_offset) < MAX) {

synchronized (Object.class) {

queue.add("a");

size++;

System.out.println("put " + queue.size());

}

}

}

}

});

pool.execute(new Runnable() {

@Override

public void run() {

while (true) {

if (_unsafe.getIntVolatile(size_base, size_offset) > 0) {

synchronized (Object.class) {

queue.poll();

size--;

System.out.println("get " + queue.size());

}

}

}

}

});

}

private static final Unsafe _unsafe = UtilUnsafe.getUnsafe();

static {

try {

size_base = _unsafe.staticFieldBase(Demo4.class.getDeclaredField("size"));

size_offset = _unsafe.staticFieldOffset(Demo4.class.getDeclaredField("size"));

} catch (Exception e) {

throw new Error(e);

}

}

private static class UtilUnsafe {

private UtilUnsafe() {

}

public static Unsafe getUnsafe() {

if (UtilUnsafe.class.getClassLoader() == null)

return Unsafe.getUnsafe();

try {

final Field fld = Unsafe.class.getDeclaredField("theUnsafe");

fld.setAccessible(true);

return (Unsafe) fld.get(UtilUnsafe.class);

} catch (Exception e) {

throw new RuntimeException("Could not obtain access to sun.misc.Unsafe", e);

}

}

}

}

换成变量地址(size_base + size_offset)的方式通过volatile直接读取,这样也可读到最新的size值。

我这个方案的意义是,size是在锁里面被写入 与 size生命为volatile变量, 这两者有点多余。:)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值