rspec/rules/S1860/java/rule.adoc

99 lines
2.9 KiB
Plaintext
Raw Normal View History

== 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.
2021-04-28 16:49:39 +02:00
Within the JDK, types which should not be used for synchronization include:
2021-04-28 16:49:39 +02:00
* `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`.
2021-04-28 16:49:39 +02:00
== How to fix it
2021-04-28 16:49:39 +02:00
Replace instances of value-based classes with a new object instance to synchronize on.
== Code examples
=== Noncompliant code example
2021-04-28 16:49:39 +02:00
[source,java,diff-id=1,diff-type=noncompliant]
2021-04-28 16:49:39 +02:00
----
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
...
2021-04-28 16:49:39 +02:00
}
synchronized(iLock) { // Noncompliant
...
2021-04-28 16:49:39 +02:00
}
synchronized(sLock) { // Noncompliant
...
2021-04-28 16:49:39 +02:00
}
synchronized(listLock) { // Noncompliant
...
2021-04-28 16:49:39 +02:00
}
----
=== Compliant solution
2021-04-28 16:49:39 +02:00
[source,java,diff-id=1,diff-type=compliant]
2021-04-28 16:49:39 +02:00
----
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
...
2021-04-28 16:49:39 +02:00
}
synchronized(lock2) { // Compliant
...
2021-04-28 16:49:39 +02:00
}
synchronized(lock3) { // Compliant
...
2021-04-28 16:49:39 +02:00
}
synchronized(lock4) { // Compliant
...
2021-04-28 16:49:39 +02:00
}
----
== Resources
2021-04-28 16:49:39 +02:00
* 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[]