将无状态回调置于BlockingQueue中是否安全?

时间:2016-04-06 14:22:09

标签: java multithreading blockingqueue

我有以下非常简单的回调接口和POJO类:

public interface Action{
    public void doAction();
}

public class Person{
     private String name;
     private String address;
     //...etc
     //GET, SET, toString
}

我将按如下方式使用它:

public class ActionExecutor{

    private static final Logger logger = LogManager.getLogger(ActionExecutor.class);
    private final BlockingQueue<Action> blockingQueue = new LinkedBlockingQueue(2000);

    public void execute(final Person p){
        //modify state of p in some way
        blockingQueue.put(new Action(){
            public void doAction(){
                logger.info("Execution started: " +p.toString );
                //do some other job
        });
    }
}

BlockingQueue这里用于实现生产者 - 消费者。

问题: 是否可以保证从BlockingQueue采取行动的消费者线程会写出正确的日志消息?即它观察到Person的正确状态?但我对此并不十分肯定。

我认为不,它不能得到保证,因为在制作人修改和制作人阅读之间订单之前没有发生。

1 个答案:

答案 0 :(得分:3)

答案是,这取决于。

如果您之后从未修改过Person实例,那么可以保证。正如所述in the docs所述,有一种发生在之前的关系:

  

内存一致性效果:与其他并发集合一样,   在将对象放入BlockingQueue之前的线程中的操作   发生在访问或删除之后的操作之前   来自另一个线程中的BlockingQueue的元素。

然而,我仍然不会这样做。如果在之后将Person实例修改为队列,那么则无法保证。您可以说记录器保证打印的状态至少与添加到队列时的状态一样。

所以消费者会看到这些修改:

public void execute(final Person p){
    //modify state of p in some way
    blockingQueue.put(new Action(){

但不是那之后的那些。并且由于在将p传递给new Action()对象后保持public void execute(final Person p){ //modify state of p in some way blockingQueue.put(new Action() { final String executionName = p.toString(); public void doAction(){ logger.info("Execution started: " + executionName); //do some other job }); } ,我会避免这种情况。相反,我会做这样的事情:

p

现在状态被捕获在最终变量中。无论当时x <- c(read.csv(file="FX.csv", sep=";", header = FALSE, dec=",")) sapply(x, typeof) 的状态如何,消费者都会看到这个价值。