Now I wrote a function for the application server and killed a lot of time for finding errors. The question of why, and not how to fix it, I want to understand what the problem is ...


The program did the following:

  1. Through the servlet updated the value of the object Водитель .
  2. The object returned the result to the client via the socket.

For this there was one method (synchronized block, so that all users would not change the value to the driver at once, then I would redo it; I cut out the code from the database):

 public synchronized void setDriverLimit(int driverId, double driverLimit) { mDriversMap.get(driverId).setMaxMoneyPerDay(new BigDecimal(driverLimit)); mDriversBroadcast.onDriverAction(ActionWrapper.builder() .action(ActionWrapper.Action.CHANGED) .object(mDriversMap.get(driverId)) .build()); } 

After calling the server, an object with a new value (limit) was recorded in the server socket, the onDriverAction method was responsible for onDriverAction , and for some reason an object appeared at the output of the client BEFORE the method call (which was in Map before the new limit was set) . 6 hours puzzled over the problem, put logs everywhere - everything works correctly, but the values ​​do not come ... The object is written to the socket with a value of, say, 10, and comes - 5! PS I’m very surprised and it’s even useful to look for whether there is such a glitch in OpenJDK, although I knew that my cant was ... :))

In the end, I decided to look at similar methods in the same class and realized that this is the only one that uses objects from the Map , rather than newly created ones. Posted by:

 public synchronized void setDriverLimit(int driverId, double driverLimit) throws SQLException { Driver driverWithNewLimit = Driver.builder() .autogeneratedIdNotUse(mDriversMap.get(driverId).getAutogeneratedIdNotUse()) .driverId(driverId) .driverName(mDriversMap.get(driverId).getDriverName()) .carNumber(mDriversMap.get(driverId).getCarNumber()) .driverPhoneNumber(mDriversMap.get(driverId).getCarNumber()) .driverPassword(mDriversMap.get(driverId).getDriverPassword()) .maxMoneyPerDay(new BigDecimal(driverLimit)) .lastToday(new BigDecimal(mDriversMap.get(driverId).getLastToday().doubleValue())) .build(); mDriversMap.replace(driverId, driverWithNewLimit); mDriversBroadcast.onDriverAction(ActionWrapper.builder() .action(ActionWrapper.Action.CHANGED) .object(driverWithNewLimit) .build()); } 

Surprisingly it all worked! The meaning of writing such a method was to avoid all sorts of references to old objects.

I forgot to mention that everything was written to the socket in the simplest way: the OutputStream taken, converted to an ObjectOutputStream and ActionWrapper arrays were ActionWrapper using the writeObject() method. Arrays, not single objects, because they were collected every 5 seconds and sent by the group.


Question: what is the reason for this behavior? Where is this thread-safe HashMap manages to store links or what is the socket referring to old links? Or maybe the problem is BigDecimal ? In general, I hope that a person who understands this will be able to paint what the matter is :).

  • business, probably, in ObjectOutputStream , it remembers links to the transferred objects. - zRrr
  • @zRrr, here are saboteurs ... Add to the answer :). - Rostislav Dugin

0