Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>Short answer: you don't need the synchronization. Both approaches are equivalent from a thread safety perspective.</p> <p>Longer answer:</p> <p>It may be worthwhile taking a step back and remembering what the synchronized block does. It does essentially two things:</p> <ol> <li>makes sure that if thread A is inside a block that's synchronized on object M, no other thread can enter a block that's synchronized on the same object M until thread A is done with its block of code</li> <li>makes sure that if thread A has done work within a block that's synchronized object M, and then finishes that block, and then thread B enters a block that's also synchronized on M, then thread B will see everything that thread A had done within its synchronized block. This is called establishing the happens-before relationship.</li> </ol> <p>Note that a synchronized method is just shorthand for wrapping the method's code in synchronized (this) { ... }.</p> <p>In addition to those two things, the Java Memory Model (JMM) guarantees that within one thread, things will happen as if they had not been reordered. (They may actually be reordered for various reasons, including efficiency -- but not in a way that your program can notice within a single thread. For instance, if you do "x = 1; y = 2" the compiler is free to switch that such that y = 2 happens before x = 1, since a single thread can't actually notice the difference. If multiple threads are accessing x and y, then it's very possible, without proper synchronization, for another thread to see y = 2 before it sees x = 1.)</p> <p>So, getting back to your original question, there are a couple interesting notes.</p> <p>First, since a synchronized method is shorthand for putting the whole method inside a "synchronized (this) { ... }" block, t1's methods and t2's methods will not be synchronized against the same reference, and thus will not be synchronized relative to each other. t1's methods will only be synchronized against the t1 object, and t2's will only be synchronized against t2. In other words, it would be perfectly fine for t1.method1() and t2.method1() to run at the same time. So, of those two things the synchronized keyword provides, the first one (the exclusivity of entering the block) isn't relevant. Things could go something like:</p> <ol> <li>t1 wants to enter method1. It needs to acquire the t1 monitor, which is not contended -- so it acquires it and enters the block</li> <li>t2. wants to enter method2. It needs to acquire the 11 monitor, which is not contended -- s it acquires it and enters the block</li> <li>t1 finishes method1 and releases its hold on the t1 monitor</li> <li>t2 finishes method1 and releases its hold on the t2 monitor</li> </ol> <p>As for the second thing synchronization does (establishing happens-before), making method1() and method2() synchronized will basically be ensuring that t1.method1() happens-before t1.method2(). But since both of those happen on the same thread anyway (the t1 thread), the JMM anyway guarantees that this will happen.</p> <p>So it actually gets even a bit uglier. If t1 and t2 did share state -- that is, synchronization would be necessary -- then making the methods synchronized would <em>not</em> be enough. Remember, a synchronized method means synchronized (this) { ... }, so t1's methods would be synchronized against t1, and t2's would be against t2. You actually wouldn't be establishing any happens-before relationship between t1's methods and t2's.</p> <p>Instead, you'd have to ensure that the methods are synchronized <em>on the same reference</em>. There are various ways to do this, but basically, it has to be a reference to an object that the two threads both know about.</p> <p>Assume t1 and t2 both know about the same reference, LOCK. Both have methods like:</p> <pre><code>method1() { synchronized(LOCK) { // do whatever } } </code></pre> <p>Now things could go something like this:</p> <ol> <li>t1 wants to enter method1. It needs to acquire the LOCK monitor, which is not contended -- so it acquires it and enters the block</li> <li>t2 wants to enter method1. It needs to acquire the LOCK monitor, which is already held by t1 -- so t2 is put on hold.</li> <li>t1 finishes method1 and releases its hold on the LOCK monitor</li> <li>t2 is now able to acquire the LOCK monitor, so it does, and starts on the meat of method1</li> <li>t2 finishes method1 and releases its hold on the LOCK monitor</li> </ol>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload