rspec/rules/S2273/java/rule.adoc

60 lines
2.2 KiB
Plaintext
Raw Normal View History

== Why is this an issue?
2023-08-11 15:13:07 +02:00
The `Object.wait(...)`, `Object.notify()` and `Object.notifyAll()` methods are used in multithreaded environments to coordinate interdependent tasks that are performed by different threads.
These methods are not thread-safe and by contract, they require the invoking `Thread` to own the object's monitor.
If a thread invokes one of these methods without owning the object's monitor an `IllegalMonitorStateException` is thrown.
2021-04-28 16:49:39 +02:00
2023-08-11 15:13:07 +02:00
== How to fix it
2023-08-11 15:13:07 +02:00
To become the owner of an object's monitor Java provides the `synchronized` keyword.
In other words, calling `Object.wait(...)`, `Object.notify()` and `Object.notifyAll()` on a given object should only be done from code synchronized on the same object.
2021-04-28 16:49:39 +02:00
2023-08-11 15:13:07 +02:00
For example, the call to `someObject.wait(...)` should be wrapped in a `synchronized(someObject){ ... }` block.
If `wait` or `notify` are invoked on `this`, then the entire method can be marked as `synchronized`.
2021-04-28 16:49:39 +02:00
2023-08-11 15:13:07 +02:00
=== Code examples
2021-04-28 16:49:39 +02:00
2023-08-11 15:13:07 +02:00
==== Noncompliant code example
2021-04-28 16:49:39 +02:00
2023-08-11 15:13:07 +02:00
[source,java,diff-id=1,diff-type=noncompliant]
2021-04-28 16:49:39 +02:00
----
2023-08-11 15:13:07 +02:00
private void performSomeAction(Object syncValue) {
2021-04-28 16:49:39 +02:00
while (!suitableCondition()){
2023-08-11 15:13:07 +02:00
syncValue.wait(); // Noncompliant, not being inside a `synchronized` block, this will raise an IllegalMonitorStateException
2021-04-28 16:49:39 +02:00
}
2023-08-11 15:13:07 +02:00
... // Perform some action
2021-04-28 16:49:39 +02:00
}
----
2023-08-11 15:13:07 +02:00
==== Compliant solution
2023-08-11 15:13:07 +02:00
[source,java,diff-id=1,diff-type=compliant]
2021-04-28 16:49:39 +02:00
----
2023-08-11 15:13:07 +02:00
private void performSomeAction(Object syncValue) {
synchronized(syncValue) {
2021-04-28 16:49:39 +02:00
while (!suitableCondition()){
2023-08-11 15:13:07 +02:00
syncValue.wait(); // Compliant, the `synchronized` block guarantees ownership of syncValue's monitor
2021-04-28 16:49:39 +02:00
}
2023-08-11 15:13:07 +02:00
... // Perform some action
2021-04-28 16:49:39 +02:00
}
}
----
2023-08-11 15:13:07 +02:00
== References
2021-04-28 16:49:39 +02:00
2023-08-11 15:13:07 +02:00
* https://docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html[Java Documentation] - Synchronized methods
* https://docs.oracle.com/javase%2F7%2Fdocs%2Fapi%2F%2F/java/lang/Object.html#wait()[Java Documentation] - java.lang.Object class and its methods
ifdef::env-github,rspecator-view[]
'''
== Implementation Specification
(visible only on this page)
=== Message
Make this call to "[wait(...)|notify()|notifyAll()]" only inside a synchronized block to be sure to hold the monitor on "[this|xxx]" object.
endif::env-github,rspecator-view[]