I say never use synchronization unless you *really really* need to. Multi-threading is a pain in the ass and synchronization makes things much more complicated, not to mention the huge performance hit.

I say never use synchronization unless you *really really* need to. Multi-threading is a pain in the ass and synchronization makes things much more complicated, not to mention the huge performance hit.

I say never use synchronization unless you *really really* need to. Multi-threading is a pain in the ass and synchronization makes things much more complicated, not to mention the huge performance hit.

I don't even get why you would want to synchronize your game.

Maybe you want 2 000 000 particles instead of 800 000? Maybe you want 1000 units instead of 300? Or maybe you just want to block and wait for something to happen without pausing your whole game.

I say never use synchronization unless you *really really* need to. Multi-threading is a pain in the ass and synchronization makes things much more complicated, not to mention the huge performance hit.

I don't even get why you would want to synchronize your game.

Maybe you want 2 000 000 particles instead of 800 000? Maybe you want 1000 units instead of 300? Or maybe you just want to block and wait for something to happen without pausing your whole game.

Okay, that came out kind of arrogant and irritated sounding... It's useful when you need to synchronize threads in some way. For example you can't modify a list from two threads at the same time. You can't even read and write to the same list from two threads at the same time. Therefore you use synchronize() blocks to acquire a lock on an object. While a thread is inside a synchronized() block, no other thread may acquire the same lock and will block (wait) until the first thread releases the lock (= exits the synchronized() block). In the above list example, you can acquire a lock on the list to ensure that it is only accessed by one thread at a time.

Multithreading is often done for performance reasons, so you want to avoid synchronizing as much as possible. Not only does too much synchronization defeat the purpose of multithreading since only one thread can work at a time, there's also a massive overhead for synchronization, so you have to know what you're doing to even get a performance increase. The potential is pretty good though. Theoretically you can get a 4x speedup on a quad core, even more with hyperthreading or more cores.

The second usage case is when you want to wait for something to happen. Maybe you're waiting for data from a network connection. If no data is received your program will be locked indefinitely, so you need to put the blocking code into a different thread so the game loop can still run independently from the network code. However, you still need to somehow pass data from the network thread to the main thread in a thread-safe way. A normal approach is to put the received data in a queue which is checked by the game loop. This queue needs to be synchronized or you'll get undefined extremely random behavior. This of course has nothing to do with gaining performance.

The only reason to not use synchronized (this) and not synchronize on some other monitor object instead is if your object might need more than one such monitor, and in that case, you probably need to split up your class design anyway to use more composition and put the synchronized methods on the relevant components instead.

You should hardly ever need to use a synchronized block; break it up into a synchronized method instead. The method call overhead is dwarfed by the synchronization overhead anyway.

Also, don't think you can just replace a synchronized block/method with some sort of Lock or other mutex mechanism: synchronization also makes sure that updates are consistent across all threads when the monitor is released, and that can only be guaranteed with synchronized (or one of the Atomic classes), not just a lock.

The other reason not to use synchronized(this) is because it exposes implementation details. Suddenly external code can lock (forever) on your mutex or notify it. Best is to have a private field holding a dummy instance or an otherwise inaccessible instance (no getter), acting as the mutex.

Hi, appreciate more people! Σ ♥ = ¾Learn how to award medals... and work your way up the social rankings!

I can't say that I've ever really run into other objects making an unauthorized grab of some other instance's monitor. I just mark methods as 'synchronized', everyone stays in their own yard, and everyone's happy.

Lock-free is your friend. Esp. lock free stuff others have written for you. Rough rule of thumb (which mean it's wrong quite a bit) is to be lock-free except under very heavy contention...and you never want to be in a heavy contention situation. Therefore, synchronized should be considered very stinky and you should wonder if you've gone horribly wrong somewhere if you write it.

Also, don't think you can just replace a synchronized block/method with some sort of Lock or other mutex mechanism: synchronization also makes sure that updates are consistent across all threads when the monitor is released, and that can only be guaranteed with synchronized (or one of the Atomic classes), not just a lock.

If you're talking about implementation of the Lock interface, then that's wrong. The spec says that all implementations must enforce the same memory barrier semantics. Not that that can be guaranteed from an interface, but you can guarantee that the built-in implementations will adhere to it.

Therefore, synchronized should be considered very stinky and you should wonder if you've gone horribly wrong somewhere if you write it.

Couldn't agree more! Learn to use lock-free mechanisms, particularly lock-free queues, for passing information around. Praxis' architecture is designed in this way - there are almost no locks anywhere in the code base (except a couple of places where they're enforced by 3rd party libs). The first part of this blog post on its architecture (and the linked to post by Ross Bencina) may explain some reasons this is a good idea in general, particularly where you want consistent timing (eg. framerate!)

Also, don't think you can just replace a synchronized block/method with some sort of Lock or other mutex mechanism: synchronization also makes sure that updates are consistent across all threads when the monitor is released, and that can only be guaranteed with synchronized (or one of the Atomic classes), not just a lock.

If you're talking about implementation of the Lock interface, then that's wrong. The spec says that all implementations must enforce the same memory barrier semantics. Not that that can be guaranteed from an interface, but you can guarantee that the built-in implementations will adhere to it.

All Lock implementations must enforce the same memory synchronization semantics as provided by the built-in monitor lock, as described in section 17.4 of The Java™ Language Specification:

A successful lock operation has the same memory synchronization effects as a successful Lock action. A successful unlock operation has the same memory synchronization effects as a successful Unlock action.

Unsuccessful locking and unlocking operations, and reentrant locking/unlocking operations, do not require any memory synchronization effects.

Huh, I stand corrected. I was under the impression that the monitor semantics only applied to the state of the Lock itself, but the javadoc is pretty clear in referencing the JLS. That's interesting, because I have screwed myself with out-of-order updates when using a Lock, which went away when I synchronized instead. Perhaps I let go of the lock too soon... I'd check the code, but I don't think I ever committed the broken version. Oh well, more anecdotal evidence that multithreading is hard.

I have a strong tendency to have strong isolation of "ownership" notions which requires virtually nothing special. I'd say the majority of my "sync" is via volatile. The most used concurrent data-structure is a fixed-length single producer/single consumer circular list (wait-free). Toss in some atomic types and that covers the majority of concurrent communication. But hey, maybe I don't get out enough.

java-gaming.org is not responsible for the content posted by its members, including references to external websites,
and other references that may or may not have a relation with our primarily
gaming and game production oriented community.
inquiries and complaints can be sent via email to the info‑account of the
company managing the website of java‑gaming.org