对象之间的私有变量共享

时间:2016-11-09 11:58:55

标签: java

我的课程看起来像

public class Sender {
    private LoggingAdapter log = Logging.getLogger(this.toString());
    private final ArrayList<CSAMessage> sentHistory = new ArrayList<>();

    public void send(final CSAMessage message) {
        doSend(message);
        sentHistory.add(message);
    }

    private void doSend(CSAMessage message) {
        //do send stuff
    }
}

问题是 - 当同时调用两个Sender类实例时,它们共享私有的sentHistory字段。在日志中它看起来像

  

调用了Sender1 send(...),将消息添加到自己的sendHistory列表中   调用Sender2 send(...),将消息添加到Sender1 sendHistory list

那怎么可能?我确定Sender1和Sender2是不同的实例,他们从不同的线程调用,但是同时进行了调用。

我已经尝试过制作变量&#39; volatile&#39; - 没有结果
这个块也没有结果

private final ArrayList<CSAMessage> sentHistory;

{
    sentHistory = new ArrayList<>();
}

仅通过课堂同步帮助

public void send(final CSAMessage message) {
    synchronized (Sender.class) {
        doSend(message);
        sentHistory.add(message);
    }
}

但这将是性能瓶颈 - 许多发件人必须能够在同一时间工作。我为什么要这样做?不同的实例必须使用它自己的变量!
还有一个已声明相同方式的日志变量,但日志变量不在对象之间共享,每个发件人都会从它自己的名称中写入日志。

1 个答案:

答案 0 :(得分:3)

标记变量final并按照您的方式初始化

private final ArrayList<CSAMessage> sentHistory = new ArrayList<>();
//      ^^^^^                                   ^^^^^^^^^^^^^^^^^^^

使多个实例完全无法共享相同的ArrayList

然而,仍有可能让多个ArrayList共享CSAMessage的相同实例。如果共享CSAMessage是可变的,则可能会产生共享错觉。例如,如果CSAMessage的{​​{1}}链接被设置为Sender呼叫的一部分,则同时进行更改可能会将消息显示为通过错误的发件人发送