GabrielBailey74
|
 |
«
Posted
2012-11-04 02:10:00 » |
|
I was wondering if anyone could give me some advice on this, without directing me to a API, rather tips on when to use it, and when not to use it? 1 2
| synchronized(this) { } |
Hope someone can help, thanks.
|
|
|
|
ra4king
|
 |
«
Reply #1 - Posted
2012-11-04 02:42:58 » |
|
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.
|
|
|
|
GabrielBailey74
|
 |
«
Reply #2 - Posted
2012-11-04 02:59:47 » |
|
Thanks, guess i'll look up on it some more, remove it from my game.
|
|
|
|
Games published by our own members! Check 'em out!
|
|
masteryoom
|
 |
«
Reply #3 - Posted
2012-11-04 03:01:28 » |
|
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. 
|
|
|
|
theagentd
|
 |
«
Reply #4 - Posted
2012-11-04 03:13:02 » |
|
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.
|
Myomyomyo.
|
|
|
masteryoom
|
 |
«
Reply #5 - Posted
2012-11-04 03:14:19 » |
|
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. Oh. 
|
|
|
|
SHC
|
 |
«
Reply #6 - Posted
2012-11-04 03:19:55 » |
|
|
|
|
|
GabrielBailey74
|
 |
«
Reply #7 - Posted
2012-11-04 03:24:14 » |
|
lol, that's the post I was looking at right after I replied to ra4king.  Thanks guys.
|
|
|
|
theagentd
|
 |
«
Reply #8 - Posted
2012-11-04 03:26:34 » |
|
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.
|
Myomyomyo.
|
|
|
GabrielBailey74
|
 |
«
Reply #9 - Posted
2012-11-04 03:29:25 » |
|
Geeze, thanks theagentd. I removed about 5 synchronized statements from the game (just posted it in WIP), seems my fps went up  (guess i had no idea about sync statements, will reserve for threads only >.<)
|
|
|
|
Games published by our own members! Check 'em out!
|
|
Agro
|
 |
«
Reply #10 - Posted
2012-11-04 03:32:47 » |
|
Wouldn't syncronhized threads block/speed up your game depending on the usage?
|
|
|
|
theagentd
|
 |
«
Reply #11 - Posted
2012-11-04 03:34:15 » |
|
Wouldn't syncronhized threads block/speed up your game depending on the usage?
Threads only work in parallel on multiple cores if they AREN'T synchronized, so you want to use as little synchronization as possible.
|
Myomyomyo.
|
|
|
GabrielBailey74
|
 |
«
Reply #12 - Posted
2012-11-04 03:44:34 » |
|
Wouldn't syncronhized threads block/speed up your game depending on the usage?
That's what I thought it was doing at first 
|
|
|
|
sproingie
|
 |
«
Reply #13 - Posted
2012-11-04 04:06:29 » |
|
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.
|
|
|
|
Riven
|
 |
«
Reply #14 - Posted
2012-11-04 04:10:59 » |
|
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!
|
|
|
sproingie
|
 |
«
Reply #15 - Posted
2012-11-04 04:20:41 » |
|
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.
|
|
|
|
Riven
|
 |
«
Reply #16 - Posted
2012-11-04 04:23:51 » |
|
The same could be said about field visibility. I like to code defensively 
|
Hi, appreciate more people! Σ ♥ = ¾ Learn how to award medals... and work your way up the social rankings!
|
|
|
ra4king
|
 |
«
Reply #17 - Posted
2012-11-04 04:27:37 » |
|
I try to avoid using 'synchronized', especially in performance critical code.
|
|
|
|
sproingie
|
 |
«
Reply #18 - Posted
2012-11-04 04:43:08 » |
|
I try to avoid using 'synchronized', especially in performance critical code.
If your program is single-threaded, synchronization is basically a no-op in a modern JVM. Of course not sharing state is also a legit way of preventing that kind of overhead.
|
|
|
|
Roquen
|
 |
«
Reply #19 - Posted
2012-11-04 06:39:15 » |
|
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.
|
|
|
|
nsigma
|
 |
«
Reply #20 - Posted
2012-11-04 12:08:18 » |
|
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!)
|
Praxis LIVE - hybrid visual IDE for (live) creative coding
|
|
|
KittenKoder
|
 |
«
Reply #21 - Posted
2012-11-04 12:13:24 » |
|
Vectors are about the only time I use it, and that's because I use vectors to communicate between threads. Otherwise I avoid it, you can manage locking inside the class if the object really needs it.
|
I am no one else.
|
|
|
sproingie
|
 |
«
Reply #22 - Posted
2012-11-04 16:29:57 » |
|
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. 
|
|
|
|
delt0r
|
 |
«
Reply #23 - Posted
2012-11-04 21:29:08 » |
|
I don't use synchronize anymore. Just use the stuff in java.util.concurrent.*, its typically the same speed or better and you have something that is generally easier to use.
|
I have no special talents. I am only passionately curious.--Albert Einstein
|
|
|
Roquen
|
 |
«
Reply #24 - Posted
2012-11-05 08:55:34 » |
|
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.
|
|
|
|
Spasi
|
 |
«
Reply #25 - Posted
2012-11-05 10:30:44 » |
|
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. Disruptor or something custom?
|
|
|
|
ra4king
|
 |
«
Reply #26 - Posted
2012-11-05 23:45:27 » |
|
I just use a ConcurrentLinkedQueue if I ever need to communicate a list of events/information between threads 
|
|
|
|
Spasi
|
 |
«
Reply #27 - Posted
2012-11-06 00:41:39 » |
|
I just use a ConcurrentLinkedQueue Be careful with that. CLQ is unbounded (no way to create back pressure) and the tail/head references sharing the same cache line causes unnecessary contention.
|
|
|
|
sproingie
|
 |
«
Reply #28 - Posted
2012-11-06 00:47:00 » |
|
To say nothing of ConcurrentLinkedQueue not having any blocking operations. I prefer ArrayBlockingQueue myself, or SynchronousQueue when I need a synchronization point (which is pretty rare)
|
|
|
|
ra4king
|
 |
«
Reply #29 - Posted
2012-11-06 01:00:24 » |
|
I just use a ConcurrentLinkedQueue Be careful with that. CLQ is unbounded (no way to create back pressure) and the tail/head references sharing the same cache line causes unnecessary contention. So....err......in English? 
|
|
|
|
|