JCIP-3-Sharing Objects

来源:互联网 发布:奶油知多少 编辑:程序博客网 时间:2024/06/05 23:54

3-Sharing Objects
3.1-Visibility
Synchronization also has another significant, and subtle, aspect: memory visibility.
You can ensure that objects are published safely either by using explicit synchronization or by taking advantage of the synchronization built into library classes.
In general, there is no guarantee that the reading thread will see a value written by another
thread on a timely basis, or even at all.
In the absence of synchronization, the compiler, processor, and runtime can do some downright weird things to the
order in which operations appear to execute. Attempts to reason about the order in which memory actions “must”
happen in insufficiently synchronized multithreaded programs will almost certainly be incorrect.
3.1.1-Stale Data
Stale data can cause serious and confusing failures such as unexpected exceptions, corrupted data
structures, inaccurate computations, and infinite loops.
3.1.2-Non-atomic 64-bit operations
The Java Memory Model requires fetch and store operations to be atomic,
but for nonvolatile long and double variables, the JVM is permitted to treat a 64-bit read or write as two separate 32-
bit operations. If the reads and writes occur in different threads, it is therefore possible to read a nonvolatile long and get back the high 32 bits of one value and the low 32 bits of another.
3.1.3-Locking and visibility
Locking is not just about mutual exclusion; it is also about memory visibility. To ensure that all threads see the most up-
to-date values of shared mutable variables, the reading and writing threads must synchronize on a common lock.
3.1.4-Volatile variables
When a field is declared volatile, the compiler and
runtime are put on notice that this variable is shared and that operations on it should not be reordered with other
memory operations. Volatile variables are not cached in registers or in caches where they are hidden from other
processors, so a read of a volatile variable always returns the most recent write by any thread.
Use volatile variables only when they simplify implementing and verifying your synchronization policy; avoid using
volatile variables when verifying correctness would require subtle reasoning about visibility. Good uses of volatile
variables include ensuring the visibility of their own state, that of the object they refer to, or indicating that an
important lifecycle event (such as initialization or shutdown) has occurred.
Locking can guarantee both visibility and atomicity; volatile variables can only guarantee visibility.
You can use volatile variables only when all the following criteria are met:
x Writes to the variable do not depend on its current value, or you can ensure that only a single thread ever
updates the value;
x The variable does not participate in invariants with other state variables; and
x Locking is not required for any other reason while the variable is being accessed.
3.2-Publication and escape
3.2.1-Safe construction practices
Do not allow the this reference to escape during construction.
Publishing an object means making it available to code outside of its current scope
3.3-Thread confinement
Thread confinement is an element of your program’s design that must be enforced by its
implementation. The language and core libraries provide mechanisms that can help in maintaining thread confinementͲ
local variables and the ThreadLocal class.but even with these, it is still the programmer’s responsibility to ensure that
thread-confined objects do not escape from their intended thread.
3.3.1-Ad-hoc thread confinement
Ad-hoc thread confinement describes when the responsibility for maintaining thread confinement falls entirely on the
implementation. Ad-hoc thread confinement can be fragile because none of the language features, such as visibility
modifiers or local variables, helps confine the object to the target thread.
3.3.2-Stack Confinement
Stack confinement (also called within-thread or thread-local
3.3.3-ThreadLocal
ThreadLocal allows you to associate a per-thread
value with a value-holding object. Thread-Local provides get and set accessor methods that maintain a separate copy
of the value for each thread that uses it, so a get returns the most recent value passed to set from the currently
executing thread.
3.4-Immutability
start
An immutable object is one whose state cannot be changed after construction. Immutable objects are inherently
thread-safe
Immutable objects are always thread-safe.
An object is immutable if:
x Its state cannot be modified after construction;
x All its fields are final;[12] and
x It is properly constructed (the this reference does not escape during construction).
3.4.1-Final Fields
Just as it is a good practice to make all fields private unless they need greater visibility [EJ Item 12], it is a good practice
to make all fields final unless they need to be mutable.
3.5-Safe publication
3.5.1-Improper Publication: When Good Objects Go Bad
3.5.2-Immutable Objects and Initialization Safety
Immutable objects can be used safely by any thread without additional synchronization, even when synchronization is
not used to publish them.
3.5.3-Safe Publication Idioms
To publish an object safely, both the reference to the object and the object’s state must be made visible to other
threads at the same time. A properly constructed object can be safely published by:
x Initializing an object reference from a static initializer;
x Storing a reference to it into a volatile field or AtomicReference;
x Storing a reference to it into a final field of a properly constructed object; or
x Storing a reference to it into a field that is properly guarded by a lock.
x Placing a key or value in a Hashtable, synchronizedMap, or Concurrent-Map safely publishes it to any thread
that retrieves it from the Map (whether directly or via an iterator);
x Placing an element in a Vector, CopyOnWriteArrayList, CopyOnWrite-ArraySet, synchronizedList, or
synchronizedSet safely publishes it to any thread that retrieves it from the collection;
x Placing an element on a BlockingQueue or a ConcurrentLinkedQueue safely publishes it to any thread that
retrieves it from the queue.
Using a static initializer is often the easiest and safest way to publish objects that can be statically constructed:
public static Holder holder = new Holder(42);
3.5.4-Effectively Immutable Objects
Safely published effectively immutable objects can be used safely by any thread without additional synchronization.
3.5.5-Mutable Objects
The publication requirements for an object depend on its mutability:
x Immutable objects can be published through any mechanism;
x Effectively immutable objects must be safely published;
x Mutable objects must be safely published, and must be either thread-safe or guarded by a lock.
3.5.6-Sharing Objects Safely
Thread-confined
Shared read-only
Shared thread-safe
Guarded
3.1-Visibility
Synchronization also has another significant, and subtle, aspect: memory visibility.
You can ensure that objects are published safely either by using explicit synchronization or by taking advantage of the synchronization built into library classes.
In general, there is no guarantee that the reading thread will see a value written by another
thread on a timely basis, or even at all.
In the absence of synchronization, the compiler, processor, and runtime can do some downright weird things to the
order in which operations appear to execute. Attempts to reason about the order in which memory actions “must”
happen in insufficiently synchronized multithreaded programs will almost certainly be incorrect.
3.1.1-Stale Data
Stale data can cause serious and confusing failures such as unexpected exceptions, corrupted data
structures, inaccurate computations, and infinite loops.
3.1.2-Non-atomic 64-bit operations
The Java Memory Model requires fetch and store operations to be atomic,
but for nonvolatile long and double variables, the JVM is permitted to treat a 64-bit read or write as two separate 32-
bit operations. If the reads and writes occur in different threads, it is therefore possible to read a nonvolatile long and get back the high 32 bits of one value and the low 32 bits of another.
3.1.3-Locking and visibility
Locking is not just about mutual exclusion; it is also about memory visibility. To ensure that all threads see the most up-
to-date values of shared mutable variables, the reading and writing threads must synchronize on a common lock.
3.1.4-Volatile variables
When a field is declared volatile, the compiler and
runtime are put on notice that this variable is shared and that operations on it should not be reordered with other
memory operations. Volatile variables are not cached in registers or in caches where they are hidden from other
processors, so a read of a volatile variable always returns the most recent write by any thread.
Use volatile variables only when they simplify implementing and verifying your synchronization policy; avoid using
volatile variables when verifying correctness would require subtle reasoning about visibility. Good uses of volatile
variables include ensuring the visibility of their own state, that of the object they refer to, or indicating that an
important lifecycle event (such as initialization or shutdown) has occurred.
Locking can guarantee both visibility and atomicity; volatile variables can only guarantee visibility.
You can use volatile variables only when all the following criteria are met:
x Writes to the variable do not depend on its current value, or you can ensure that only a single thread ever
updates the value;
x The variable does not participate in invariants with other state variables; and
x Locking is not required for any other reason while the variable is being accessed.
3.2-Publication and escape
3.2.1-Safe construction practices
Do not allow the this reference to escape during construction.
Publishing an object means making it available to code outside of its current scope
3.3-Thread confinement
Thread confinement is an element of your program’s design that must be enforced by its
implementation. The language and core libraries provide mechanisms that can help in maintaining thread confinementͲ
local variables and the ThreadLocal class.but even with these, it is still the programmer’s responsibility to ensure that
thread-confined objects do not escape from their intended thread.
3.3.1-Ad-hoc thread confinement
Ad-hoc thread confinement describes when the responsibility for maintaining thread confinement falls entirely on the
implementation. Ad-hoc thread confinement can be fragile because none of the language features, such as visibility
modifiers or local variables, helps confine the object to the target thread.
3.3.2-Stack Confinement
Stack confinement (also called within-thread or thread-local
3.3.3-ThreadLocal
ThreadLocal allows you to associate a per-thread
value with a value-holding object. Thread-Local provides get and set accessor methods that maintain a separate copy
of the value for each thread that uses it, so a get returns the most recent value passed to set from the currently
executing thread.
3.4-Immutability
start
An immutable object is one whose state cannot be changed after construction. Immutable objects are inherently
thread-safe
Immutable objects are always thread-safe.
An object is immutable if:
x Its state cannot be modified after construction;
x All its fields are final;[12] and
x It is properly constructed (the this reference does not escape during construction).
3.4.1-Final Fields
Just as it is a good practice to make all fields private unless they need greater visibility [EJ Item 12], it is a good practice
to make all fields final unless they need to be mutable.
3.5-Safe publication
3.5.1-Improper Publication: When Good Objects Go Bad
3.5.2-Immutable Objects and Initialization Safety
Immutable objects can be used safely by any thread without additional synchronization, even when synchronization is
not used to publish them.
3.5.3-Safe Publication Idioms
To publish an object safely, both the reference to the object and the object’s state must be made visible to other
threads at the same time. A properly constructed object can be safely published by:
x Initializing an object reference from a static initializer;
x Storing a reference to it into a volatile field or AtomicReference;
x Storing a reference to it into a final field of a properly constructed object; or
x Storing a reference to it into a field that is properly guarded by a lock.
x Placing a key or value in a Hashtable, synchronizedMap, or Concurrent-Map safely publishes it to any thread
that retrieves it from the Map (whether directly or via an iterator);
x Placing an element in a Vector, CopyOnWriteArrayList, CopyOnWrite-ArraySet, synchronizedList, or
synchronizedSet safely publishes it to any thread that retrieves it from the collection;
x Placing an element on a BlockingQueue or a ConcurrentLinkedQueue safely publishes it to any thread that
retrieves it from the queue.
Using a static initializer is often the easiest and safest way to publish objects that can be statically constructed:
public static Holder holder = new Holder(42);
3.5.4-Effectively Immutable Objects
Safely published effectively immutable objects can be used safely by any thread without additional synchronization.
3.5.5-Mutable Objects
The publication requirements for an object depend on its mutability:
x Immutable objects can be published through any mechanism;
x Effectively immutable objects must be safely published;
x Mutable objects must be safely published, and must be either thread-safe or guarded by a lock.
3.5.6-Sharing Objects Safely
Thread-confined
Shared read-only
Shared thread-safe
Guarded
思维导图

0 0
原创粉丝点击