[QFJ-879] SystemTime currentTimeMillis is synchronized Created: 26/Feb/16  Updated: 21/Apr/16  Resolved: 08/Mar/16

Status: Closed
Project: QuickFIX/J
Component/s: Engine
Affects Version/s: 1.6.0, 1.6.1
Fix Version/s: 1.6.2

Type: Bug Priority: Default
Reporter: Guido Medina Assignee: Guido Medina
Resolution: Fixed Votes: 0
Labels: None


 Description   

The class SystemTime was created to wrap a system time source primarily for unit testing (according to its JavaDocs) but it ended up been used globally so many important classes are obtaining the current time in millis using a synchronized call for no reason.

Can you please check if such thing is needed? If so let me know so that I can send a PR via Git.



 Comments   
Comment by Guido Medina [ 26/Feb/16 ]

I'm only referring to currentTimeMillis() method which is synchronized, if you search its usages it will show some important classes that get the time from it as intended, every message sent is time stamped, if you have more than one concurrent session sending prices for example or any other high frequency message, you end up locking for no reason as System.currentTimeMillis() is just a OS global variable (most likely an atomic variable) that is constantly updated.

Comment by Christoph John [ 29/Feb/16 ]

I assume that currentTimeMillis() is synchronized because setTimeSource() is also synchronized, so that it is made sure that always the correct systemTimeSource is used. But setTimeSource() is only used for unit tests, so maybe we can ignore that.

Comment by Guido Medina [ 29/Feb/16 ]

Not necessarily, you could leave the setter synchronized to create a memory barrier, say; you want other threads to see that you actually updated the time source.
Another way is to make the time source volatile but that would be slower than having the memory barrier at the setter.
If you think about it, the time source is updated not so frequent if ever, if the time source need to block then let it block at its implementation.
If you are sending many messages like price updates it is not good to synchronize.

Comment by Christoph John [ 29/Feb/16 ]

How will the other threads see the updated timeSource variable if they do not synchronize on it? If I'm not mistaken then synchronizing only the setter could lead to the situation where other threads might read/get old states of the timeSource variable.

Comment by Guido Medina [ 29/Feb/16 ]

Is how newer Java Memory Model work, at least Java 6+; the next read in another thread will read the updated value, synchronizing in both sides is only useful if you need one thread accessing such variable at the same time.

volatile resolves both concerns but then introduce an unnecessary CAS, the atomic-ity of such variable isn't that important.

Comment by Guido Medina [ 29/Feb/16 ]

You might as well remove both synchronize, since JMM after Java 6+ will take care of it.

Comment by Guido Medina [ 29/Feb/16 ]

I'm up for volatile, I don't think is that bad after all. Let me know what you think, maybe I'm just bargaining 1ns

Comment by Guido Medina [ 29/Feb/16 ]

I just force updated the branch with a different commit, synchronization there removed completely and changed for a volatile.

Comment by Guido Medina [ 29/Feb/16 ]

I can't make up my mind, the only reason I changed it to volatile is to give you (and other developers) a sense of safety, but I know that after JDK 6+ the JMM will clear any cache with any variable been updated inside a synchronized block hence it is not that weird to see synchronized for writes and nothing for read (a faster CAS), in fact if you go to LMAX disruptor code you will find weirdness like that one everywhere abusing the JDK JMM in order to gain performance.

So I would investigate in your side to get the feeling of safety for this, as you mentioned before the time source is only updated/changed while testing and it is only done before the tests start (it wouldn't make sense to change the time source while the tests are running)

I'll redo the push again with synchronized at set only again. Sorry for the many comments and confusion.

Comment by Christoph John [ 29/Feb/16 ]

No problem. Thanks for your input.
I was only looking this up in "Java Concurrency in Practice" but it is from 2006. Here is a quote on StackOverflow: http://stackoverflow.com/a/11459616 So it might be that this has changed in the meantime.
Anyway, for me it is OK to remove the synchronization from the getter since the setter is only used for unit testing. Let's hope that the build will be stable.

Comment by Guido Medina [ 29/Feb/16 ]

Yeah, I was looking at that one too to be completely certain and other old sources, it should be OK because (you can look at usages of setTimeSource method) setTimeSource method is called at the tests setup so it is unlikely such thing will happen.

Comment by Guido Medina [ 03/Mar/16 ]

Re-pushed with volatile, screw it, volatile will keep it correct and thread safe as writes are visible as soon as done, but TBH it is still slower than no volatile at all, though without it there is a risk of not seeing the value at all if you change the time source after some other thread have started.

At least volatile won't block concurrent sessions from getting the current time.

Generated at Fri May 03 15:22:23 UTC 2024 using JIRA 7.5.2#75007-sha1:9f5725bb824792b3230a5d8716f0c13e296a3cae.