我的课程看起来像
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);
}
}
但这将是性能瓶颈 - 许多发件人必须能够在同一时间工作。我为什么要这样做?不同的实例必须使用它自己的变量!
还有一个已声明相同方式的日志变量,但日志变量不在对象之间共享,每个发件人都会从它自己的名称中写入日志。
答案 0 :(得分:3)
标记变量final
并按照您的方式初始化
private final ArrayList<CSAMessage> sentHistory = new ArrayList<>();
// ^^^^^ ^^^^^^^^^^^^^^^^^^^
使多个实例完全无法共享相同的ArrayList
。
然而,仍有可能让多个ArrayList
共享CSAMessage
的相同实例。如果共享CSAMessage
是可变的,则可能会产生共享错觉。例如,如果CSAMessage
的{{1}}链接被设置为Sender
呼叫的一部分,则同时进行更改可能会将消息显示为通过错误的发件人发送