Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Java concurrency guidelines.pdf
Скачиваний:
16
Добавлен:
23.05.2015
Размер:
1.35 Mб
Скачать

VNA01-J

2.2VNA01-J. Ensure visibility of shared references to immutable objects

A common misconception is that shared references to immutable objects are visible across multiple threads as soon as they are updated. For example, a developer can mistakenly believe that a class containing fields referring to only immutable objects is immutable and, consequently, thread-safe.

Section 14.10.2, “Final Fields and Security” of Java Programming Language, Fourth Edition states [Arnold 2006]

The problem is that, while the shared object is immutable, the reference used to access the shared object is itself shared and often mutable. Consequently, a correctly synchronized program must synchronize access to that shared reference, but often programs do not do this, because programmers do not recognize the need to do it.

References to both immutable and mutable objects must be made visible to all the threads. Immutable objects can be shared safely among multiple threads. However, mutable objects may not be fully constructed when their references are made visible. Guideline “TSM03-J. Do not publish partially initialized objects” on page 162 describes object construction and visibility issues specific to mutable objects.

2.2.1Noncompliant Code Example

This noncompliant code example consists of the immutable Helper class:

// Immutable Helper

public final class Helper { private final int n;

public Helper(int n) { this.n = n;

}

// ...

}

and a mutable Foo class:

final class Foo { private Helper helper;

public Helper getHelper() { return helper;

}

public void setHelper(int num) { helper = new Helper(num);

}

}

CMU/SEI-2010-TR-015 | 13

VNA01-J

The getHelper() method publishes the mutable helper field. Because the Helper class is immutable, it cannot be changed after it is initialized. Furthermore, because Helper is immutable, it is always constructed properly before its reference is made visible in compliance with guideline “TSM03-J. Do not publish partially initialized objects” on page 162. Unfortunately, a separate thread could observe a stale reference in the helper field of the Foo class.

2.2.2Compliant Solution (Synchronization)

This compliant solution synchronizes the methods of the Foo class to ensure that no thread sees a stale Helper reference.

final class Foo { private Helper helper;

public synchronized Helper getHelper() { return helper;

}

public synchronized void setHelper(int num) { helper = new Helper(num);

}

}

The immutable Helper class remains unchanged.

2.2.3Compliant Solution (volatile)

References to immutable member objects can be made visible by declaring them volatile.

final class Foo {

private volatile Helper helper;

public Helper getHelper() { return helper;

}

public void setHelper(int num) { helper = new Helper(num);

}

}

The immutable Helper class remains unchanged.

CMU/SEI-2010-TR-015 | 14

VNA01-J

2.2.4Compliant Solution (java.util.concurrent Utilities)

This compliant solution wraps the immutable Helper object within an AtomicReference wrapper that can be updated atomically.

final class Foo {

private final AtomicReference<Helper> helperRef = new AtomicReference<Helper>();

public Helper getHelper() { return helperRef.get();

}

public void setHelper(int num) { helperRef.set(new Helper(num));

}

}

The immutable Helper class remains unchanged.

2.2.5Risk Assessment

The assumption that classes containing immutable objects are immutable is incorrect and can cause serious thread-safety issues.

Guideline

Severity

Likelihood

Remediation Cost

Priority

Level

VNA01-J

low

probable

medium

P4

L3

2.2.6References

[Arnold 2006] Section 14.10.2, “Final Fields and Security”

[Goetz 2006] Section 3.4.2, “Example: Using Volatile to Publish Immutable Objects”

[Sun 2009b]

CMU/SEI-2010-TR-015 | 15

VNA02-J

2.3VNA02-J. Ensure that compound operations on shared variables are atomic

Compound operations are operations that consist of more than one discrete operation. Expressions that include postfix or prefix increment (++), postfix or prefix decrement (--), or compound assignment operators always result in compound operations. Compound assignment expressions use operators such as *=, /=, %=, +=, -=, <<=, >>=, >>>=, ^=, and |= [Gosling 2005]. Compound operations on shared variables must be performed atomically to prevent data races and race conditions.

For information about the atomicity of a grouping of calls to independently atomic methods that belong to thread-safe classes, see guideline “VNA03-J. Do not assume that a group of calls to independently atomic methods is atomic” on page 23.

The Java Language Specification also permits reads and writes of 64-bit values to be non-atomic. For more information, see guideline “VNA05-J. Ensure atomicity when reading and writing 64bit values” on page 33.

2.3.1Noncompliant Code Example (Logical Negation)

This noncompliant code example declares a shared boolean flag variable and provides a toggle() method that negates the current value of flag.

final class Flag {

private boolean flag = true;

public void toggle() { // Unsafe flag = !flag;

}

public boolean getFlag() { // Unsafe return flag;

}

}

Execution of this code may result in a data race because the value of flag is read, negated, and written back.

CMU/SEI-2010-TR-015 | 16

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]