All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.sonar.l10n.java.rules.java.S1860.html Maven / Gradle / Ivy

There is a newer version: 8.6.0.37351
Show newest version

Why is this an issue?

In Java, value-based classes are those for which instances are final and immutable, like String, Integer and so on, and their identity relies on their value and not their reference. When a variable of one of these types is instantiated, the JVM caches its value, and the variable is just a reference to that value. For example, multiple String variables with the same value "Hello world!" will refer to the same cached string literal in memory.

The synchronized keyword tells the JVM to only allow the execution of the code contained in the following block to one Thread at a time. This mechanism relies on the identity of the object that is being synchronized between threads, to prevent that if object X is locked, it will still be possible to lock another object Y.

It means that the JVM will fail to correctly synchronize threads on instances of the aforementioned value-based classes, for instance:

// These variables "a" and "b" will effectively reference the same object in memory
Integer a = 0;
Integer b = 0;

// This means that in the following code, the JVM could try to lock and execute
// on the variable "a" because "b" was notified to be released, as the two Integer variables
// are the same object to the JVM
void syncMethod(int x) {
    synchronized (a) {
        if (a == x) {
        // ... do something here
        }
    }
    synchronized (b) {
        if (b == x) {
        // ... do something else
        }
    }
}

This behavior can cause unrelated threads to deadlock with unclear 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

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

private static final Object lock1 = new Object();
private static final Integer iLock = new Integer(42);
private static final String sLock = new String("A brand new string in memory!");
private static final List<String> listLock = new ArrayList<>();

public void doSomething() {

  synchronized(lock1) { // Compliant
      ...
  }
  synchronized(iLock) { // Compliant
      ...
  }
  synchronized(sLock) { // Compliant
      ...
  }
  synchronized(listLock) { // Compliant
      ...
  }

Resources





© 2015 - 2024 Weber Informatics LLC | Privacy Policy