I've not much experience with threading, but I wrote a nifty non-blocking sequential Id generator with Atomics.... It got me a very significant performance boost in testing. Now I wonder why anyone would use synchronized since it is so much slower... is there a reason on modern 64 bit multi-core hardware? Others are asking me about Atomics now. I would love to be able to tell them to never use that keyword unless they are deploying to ancient hardware.
-
Atomics have limited, single values operations. If you want to update more than one thing at a time,or a data structure which can touch multiple values e.g. HashMap, you need synchronized. – Peter Lawrey Aug 17 '13 at 05:38
-
...unless you encapsulate these in a class and then use AtomicReference? – user447607 Aug 22 '13 at 12:48
-
AtomicReference is faster than synchronized but has a limit set of operations. You cannot use it to update a mutable object or objects for example. – Peter Lawrey Aug 23 '13 at 07:28
5 Answers
Because you can't do multiple actions exclusively using only atomics (well, technically you can, because you can implement a "lock" using atomics, but i think that's beside the point). you also can't do a blocking wait using atomics (you can do a busy wait, but that's almost always a bad idea).
here's an exercise for the OP: write a program which writes timestamped log messages using multiple threads to the same file where the messages must show up in the file in timestamp order. implement this using only atomics, but without re-inventing ReentrantLock/synchronized.

- 52,909
- 5
- 76
- 118
-
Are you sure? What about: http://stackoverflow.com/questions/8213089/how-to-block-and-wait-using-atomicboolean – user447607 Aug 17 '13 at 03:21
-
@user447607 - what about it? the accepted answer is a busy loop, which is exactly what i said was bad. try running a program like that and watch it peg your cpu at 100% when it is "blocked". – jtahlborn Aug 17 '13 at 03:23
-
@user447607 - oh, i just noticed that the accepted answer had a magical "wait on some object" in pseudo-code at the end. nice non-answer. i'd love to see how that is implemented without locks. – jtahlborn Aug 17 '13 at 03:25
-
The busy loop is a common response for how to use Atomics for X... what I've been hearing for an explanation is that the busy loop is to cover an increasingly rare situation that it is actually needed. What they say is that the process granularity is so high that close to the bare metal that the loops should iterate only a very few times in the case where it does. Increasingly rare because process granularity goes up as CPU's get more powerful. That is what I'm hearing & reading in any case. – user447607 Aug 22 '13 at 19:56
-
@user447607 - that only makes sense in situations where you expect every thread to make progress relatively soon. if one thread needs to wait a while for another thread, then busy loops are a terrible solution. – jtahlborn Aug 23 '13 at 00:39
-
OK, that's certainly true however if I put the other threads to sleep haven't I effectively done the same thing as a sync block without using one... would this be faster? Then at the end of the block I can revive one or all of them. Also assumes I have access to the threads in question. – user447607 Aug 23 '13 at 15:52
-
@user447607 - you can't put threads to sleep and wake them up without wait/notify. the only thing you can do is put them to sleep for a set amount of time, which amounts to a sleep/busy loop. then you have to pick the "right" amount of time so that they respond "quickly" but don't kill your cpu. – jtahlborn Aug 23 '13 at 17:43
-
OK, I'll accept thread management itself as an example of a use case better implemented with synchronization than Atomics, although not in all cases. For the record, any accessible reference gives access to wait/notify. ...but if the CURRENT thread needs to wait based on complex threaded conditions then a synch block seems like the best option. – user447607 Aug 25 '13 at 20:27
-
The difference seems to be managing threaded activities vrs. managing access to data. I've done the former but not the later. – user447607 Aug 25 '13 at 20:33
Now I wonder why anyone would use synchronized since it is so much slower...
Maybe because speed isn't everything.
In fact, if you looked objectively at the overall performance benefit of using your "nifty" generator on a real application, I suspect you will find that it is too small to matter. Profiling the application will tell you that.
Then there is the issue of whether your benchmarking is actually valid; i.e. whether you are doing the things that are needed to avoid misleading effects like JVM warmup anomalies, optimization anomalies, and so on. And whether you are (actually) measuring the contended and uncontended cases.
Is there a viable use case where Java synchronized keyword is better than Atomics?
That's easy.
Any situation where you require exclusive access to one or more data structures to perform a sequence of operations, or an operation that is not intrinsically thread-safe. The AtomicXxx
types don't support this kind of thing.
I would love to be able to tell them to never use that keyword unless they are deploying to ancient hardware.
Don't tell them that. It is incorrect. In fact, if you are new to Java threads, I recommend that you read "Java Concurrency in Practice" by Goetz et al before you start advising people.

- 698,415
- 94
- 811
- 1,216
-
Can't I use a class to encapsulate references to the data structures and then guard that with an AtomicReference? – user447607 Aug 22 '13 at 12:38
-
BTW, We did profile it and the improvement in speed was by 40%. It's sacrificing simplicity for performance but I'm quite sure I could handle several operations and data structures as the application in question does just that. Can my colleagues understand it? Not so much. Solution I've proposed is to encapsulate the operations in a re-usable library so they don't have to. – user447607 Aug 22 '13 at 12:45
-
@user447607 - I don't see how that idea would solve the problem. If you have a specific solution, code it and I'll give you an opinion. – Stephen C Aug 22 '13 at 15:33
-
@user447607 - Are you saying that it gave you a 40% improvement in speed for your application? If not, you have missed my point. A 40% improvement on some benchmark does not signify anything if your benchmark is not realistic, or the thing you are benchmarking doesn't contribute much to over-all system behaviour. – Stephen C Aug 22 '13 at 15:39
-
Well the question itself was admittedly a generalization. Yes, we got a 40% speed boost by using Atomics. The fundamental problem with that particular application was that EVERY thread was going to need a generated ID. – user447607 Aug 22 '13 at 19:45
Depends on what you are doing - if you only need the functionality that an atomic provides you, then yes, there would be no need to do the same work yourself (using the synchronized keyword). However, many multithreaded applications do things a lot more complicated than just needing increment a number atomically.
For example, you might need a unit of work to be done where you modify several data structures in memory and all of that has to happen without interference - you could use a synchronized function or block for that.

- 10,917
- 9
- 44
- 63
-
Couldn't I put them in class and use an AtomicReference to the class? ...or protect an if block with an AtomicBoolean? if (...the AtomicBollean Is true, set it to false) {...blah} – user447607 Aug 17 '13 at 03:16
-
AtomicReference only guarantees that you can get/set it atomically. It doesn't control access to the actual object itself. On if ... AtomicBoolean ... what happens after the if statement executes? As soon as control returns back to your function, the value might change again. Context switching from thread to thread can (and does) occur at any time, so even just one line of code is enough for things to get messed up. I've experienced this many times. – Brad Peabody Aug 17 '13 at 03:41
-
Actually I'm not sure about that. The compareAndSet method is Atomic and returns true or false... so if I put it in an if statement, doesn't that mean that I can control access on a single thread basis within the If block? Might not be AtomicReference... might be an AtomicBoolean which you use to control access. – user447607 Aug 22 '13 at 19:58
-
Same issue - compareAndSet() only guarantees atomicity within that function (compareAndSet). The rest of your if statement and related blocks of code are where you are going to have a synchronization problem. I suggest writing out an example of some code using this, and then make a note of which lines would cause the program to do something erratic/wrong if they occurred at the same time as another such line in another thread, that should help clarify. (Edit your question to to include a real example if you'd like to discuss further.) – Brad Peabody Aug 22 '13 at 22:13
-
We conducted an experiment during the project wherein we checked to see if an if block could be used like this. It seems that the result to an atomic call is returned to only the thread that called it. ...or at least we were not able to entice the system to do otherwise. Since the method completes in it's entirety before another thread can change the value within, the returned value is different on the next threads attempt. That's the theory based on the observed behaviour at least. I'll see if I can write up an example. Your not the first to ask. ;-) – user447607 Aug 23 '13 at 15:57
From what I understand, the synchronized keyword is actually a moderately heavyweight recursive (re-entrant) lock.
For instance, the following (horrible) code would not deadlock:
public static Object lock = new Object();
int recurCount = 0;
public int fLocktorial(int n) {
synchronized(lock) {
recurCount++;
if (n <= 0)
return 1;
return n * fLocktorial(n-1);
}
}
Implementing this requires the maintenance of additional state and logic within the lock, which may contribute to its lower performance over atomics and other primitives. However, it does allow you to grab locks arbitrarily inside functions, without worrying if a caller has already obtained the lock. Locks implemented naively using Atomics would deadlock in this case.
Additionally, synchronized may yield performance benefits if large amounts of processing are done within the lock. Getting a lock only has a performance hit once, while atomics force a core synchronization per operation. This flushes the processor pipeline, impacting performance.

- 33
- 4
-
depends whether or not you implement locks using atomics which were re-entrant. of course, it would make no sense to do this because you could just use the built in lock implementations... – jtahlborn Aug 17 '13 at 03:30
-
So... the built-in locks are just as performant as Atomics? This was not my experience. My code posse at work tried one of them and the Atomics blew it away performance wise. It's the end of the week and it's been a hard one so I'm resisting the urge to write code on my day off. ;-) Beautiful thing about the web is that somebody somewhere has probably published a Proof Of Concept. If not, I may wind up writing it anyway. :-/ – user447607 Aug 17 '13 at 03:42
-
Ouch. I just realized my weak ain't over yet. Deployment at 1159pm. :-/ – user447607 Aug 17 '13 at 03:43
-
@user447607 - locks are just as performant as atomics at _what specifically_? incrementing a single int? no, that's why AtomicInteger was invented in the first place. doing all the things that locks can do... well that's a different story. – jtahlborn Aug 17 '13 at 03:45
-
@user447607 - also, you should be aware that ReentrantLock may be faster than synchronized. there was a point in time where it was much faster (being a newer implementation), but i think the performance gap has bee narrowed in recent java versions due to improvements in synchronized. – jtahlborn Aug 17 '13 at 03:46
-
@jtahlborn depends on the "fair" factor. a fair ReentrantLock is much slower. `synchronized` seems to sit between fair and unfair ReentrantLock – ZhongYu Aug 17 '13 at 03:51
-
@zhong.j.yu - heh, "fair" enough. i haven't followed all the details, just know that there were some differences. – jtahlborn Aug 17 '13 at 04:05
Conceptually, a critical section protected by a lock transform state from one valid state to another.
int x, y; // invariant: x==y
void inc()
synchronized(lock)
x++;
y++;
void dec()
...
We could encapsulate the state in an object, and atomically change the object.
class State
final int x, y;
State(int x, y) { ... }
volatile State state;
void inc()
do
State s = state;
State s2 = new State(s.x+1, s.y+1);
while( ! compareAndSet( "state", s, s2) ) // use Unsafe or something
Is that better? not necessarily. It is appealing, and it's simpler when states get more complicated; but it's probably slower in most cases.

- 19,446
- 5
- 33
- 61