开发者

Confusing use of synchronized in Java: pattern or anti-pattern?

开发者 https://www.devze.com 2023-04-10 08:02 出处:网络
I\'m doing a code review for a change in a Java product I don\'t own开发者_运维技巧.I\'m not a Java expert, but I strongly suspect that this is pointless and indicates a fundamental misunderstanding o

I'm doing a code review for a change in a Java product I don't own开发者_运维技巧. I'm not a Java expert, but I strongly suspect that this is pointless and indicates a fundamental misunderstanding of how synchronization works.

synchronized (this) {
    this.notify();
}

But I could be wrong, since Java is not my primary playground. Perhaps there is a reason this is done. If you can enlighten me as to what the developer was thinking, I would appreciate it.


It certainly is not pointless, you can have another thread that has a reference to the object containing the above code doing

synchronized(foo) {
    foo.wait();
}

in order to be woken up when something happens. Though, in many cases it's considered good practice to synchronize on an internal/private lock object instead of this.

However, only doing a .notify() within the synchronization block could be quite wrong - you usually have some work to do and notify when it's done, which in normal cases also needs to be done atomically in regards to other threads. We'd have to see more code to determine whether it really is wrong.


If that is all that is in the synchonized block then it is an antipattern, the point of synchronizing is to do something within the block, setting some condition, then call notify or notifyAll to wake up one or more waiting threads.

When you use wait and notify you have to use a condition variable, see this Oracle tutorial:

Note: Always invoke wait inside a loop that tests for the condition being waited for. Don't assume that the interrupt was for the particular condition you were waiting for, or that the condition is still true.

You shouldn't assume you received a notification just because a thread exited from a call to Object#wait, for multiple reasons:

  • When calling the version of wait that takes a timeout value there's no way to know whether wait ended due to receiving a notification or due to timing out.

  • You have to allow for the possibility that a Thread can wake up from waiting without having received a notification (the "spurious wakeup").

  • The waiting thread that receives a notification still has to reacquire the lock it gave up when it started waiting, there is no atomic linking of these two events; in the interval between being notified and reacquiring the lock another thread can act and possibly change the state of the system so that the notification is now invalid.

  • You can have a case where the notifying thread acts before any thread is waiting so that the notification has no effect. Assuming one thread will enter a wait before the other thread will notify is dangerous, if you're wrong the waiting thread will hang indefinitely.

So a notification by itself is not good enough, you end up guessing about whether a notification happened when the wait/notify API doesn't give you enough information to know what's going on. Even if other work the notifying thread is doing doesn't require synchronization, updating the condition variable does; there should at least be an update of the shared condition variable in the synchronized block.


This is perfectly fine. According to the Java 6 Object#notify() api documentation:

This method should only be called by a thread that is the owner of this object's monitor.


This is generally not a anti-pattern, if you still want to use intrinsic locks. Some may regard this as an anti pattern, as the new explicit locks from java.util.concurrent are more fine grained.

But your code is still valid. For instance, such code can be found in a blocking queue, when an blocking operation has succeeded and another waiting thread should be notified. Note however that concurrency issues are highly dependent on the usage and the surrounding code, so your simple snippet is not that meaningful.


The Java API documentation for Object.notify() states that the method "should only be called by a thread that is the owner of this object's monitor". So the use could be legitimate depending upon the surrounding context.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号