rspec/rules/S1860/java/rule.adoc

99 lines
2.9 KiB
Plaintext

== Why is this an issue?
Instances of value-based classes, which are pooled and potentially reused, should not be used for synchronization. If they are, it can cause unrelated threads to deadlock with unhelpful stacktraces.
Within the JDK, types which should not be used for synchronization include:
* `String` literals
* Primitive wrapper classes in `java.lang` (such as `Boolean` with `Boolean.FALSE` and `Boolean.TRUE`)
* The class `java.lang.Runtime.Version`
* The `Optional*` classes in `java.util`: `Optional`, `OptionalInt`, `OptionalLong`, and `OptionalDouble`
* Various classes in the `java.time` API: `Instant`, `LocalDate`, `LocalTime`, `LocalDateTime`, `ZonedDateTime`, `ZoneId`, `OffsetTime`, `OffsetDateTime`, `ZoneOffset`, `Duration`, `Period`, `Year`, `YearMonth`, and `MonthDay`
* Various classes in the `java.time.chrono` API: `MinguoDate`, `HijrahDate`, `JapaneseDate`, and `ThaiBuddhistDate`
* The interface `java.lang.ProcessHandle` and its implementation classes
* The implementation classes of the collection factories in `java.util`: `List.of`, `List.copyOf`, `Set.of`, `Set.copyOf`, `Map.of`, `Map.copyOf`, `Map.ofEntries`, and `Map.entry`.
== How to fix it
Replace instances of value-based classes with a new object instance to synchronize on.
== Code examples
=== Noncompliant code example
[source,java,diff-id=1,diff-type=noncompliant]
----
private static final Boolean bLock = Boolean.FALSE;
private static final Integer iLock = Integer.valueOf(0);
private static final String sLock = "LOCK";
private static final List<String> listLock = List.of("a", "b", "c", "d");
public void doSomething() {
synchronized(bLock) { // Noncompliant
...
}
synchronized(iLock) { // Noncompliant
...
}
synchronized(sLock) { // Noncompliant
...
}
synchronized(listLock) { // Noncompliant
...
}
----
=== Compliant solution
[source,java,diff-id=1,diff-type=compliant]
----
private static final Object lock1 = new Object();
private static final Object lock2 = new Object();
private static final Object lock3 = new Object();
private static final Object lock4 = new Object();
public void doSomething() {
synchronized(lock1) { // Compliant
...
}
synchronized(lock2) { // Compliant
...
}
synchronized(lock3) { // Compliant
...
}
synchronized(lock4) { // Compliant
...
}
----
== Resources
* https://wiki.sei.cmu.edu/confluence/x/1zdGBQ[Do not synchronize on objects that may be reused - CERT, LCK01-J.]
* https://openjdk.java.net/jeps/390[JEP 390: Warnings for Value-Based Classes - OpenJDK]
* https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/doc-files/ValueBased.html[Value-based Classes - Java SE 17 API Documentation]
ifdef::env-github,rspecator-view[]
'''
== Implementation Specification
(visible only on this page)
=== Message
Synchronize on a new "Object" instead.
'''
== Comments And Links
(visible only on this page)
=== relates to: S2445
endif::env-github,rspecator-view[]