Asprelis Asprelis - 26 days ago 16
Java Question

Private variable shares between objects

I have class that looks like

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
}
}


The problem is - when two instances of Sender class are called in same time, they share private sentHistory field. In logs it looks like


Sender1 send(...) was called, message was added to own sendHistory list

Sender2 send(...) was called, message was added to Sender1 sendHistory list


How is that posiible? I'm shure that Sender1 and Sender2 are different instances, they called from different threads, but call was made in same time.


I already tried to make variable 'volatile' - no result

This block gives no result too

private final ArrayList<CSAMessage> sentHistory;

{
sentHistory = new ArrayList<>();
}


Only synchronizing via class helps

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


But this will be performance bottleneck - many Senders must be able to work in same time. And why should i do so? Different instances must use it's own variables!

There are also log variable that has been declared same way, but logging variable not shared between objects, every Sender write logs from it's own name.

Answer

Marking the variable final and initializing it the way you did

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

makes it absolutely impossible for multiple instances to share the same ArrayList.

What remains possible, however, is for multiple ArrayLists to share the same instances of CSAMessage. In cases when shared CSAMessages are mutable, it is possible to create an illusion of sharing. For example, if CSAMessage has a link back to Sender which is set as part of a send call, making a change concurrently may present the message as if it were sent through a wrong sender.

Comments