com.strobel.core.Fences Maven / Gradle / Ivy
package com.strobel.core;
/*
* Written by Doug Lea with assistance from members of JCP JSR-166
* Expert Group and released to the public domain, as explained at
* http://creativecommons.org/publicdomain/zero/1.0/
*/
/**
* A set of methods providing fine-grained control over happens-before
* and synchronization order relations among reads and/or writes. The
* methods of this class are designed for use in uncommon situations
* where declaring variables {@code volatile} or {@code final}, using
* instances of atomic classes, using {@code synchronized} blocks or
* methods, or using other synchronization facilities are not possible
* or do not provide the desired control.
*
* Memory Ordering. There are three methods for controlling
* ordering relations among memory accesses (i.e., reads and
* writes). Method {@code orderWrites} is typically used to enforce
* order between two writes, and {@code orderAccesses} between a write
* and a read. Method {@code orderReads} is used to enforce order
* between two reads with respect to other {@code orderWrites} and/or
* {@code orderAccesses} invocations. The formally specified
* properties of these methods described below provide
* platform-independent guarantees that are honored by all levels of a
* platform (compilers, systems, processors). The use of these
* methods may result in the suppression of otherwise valid compiler
* transformations and optimizations that could visibly violate the
* specified orderings, and may or may not entail the use of
* processor-level "memory barrier" instructions.
*
*
Each ordering method accepts a {@code ref} argument, and
* controls ordering among accesses with respect to this reference.
* Invocations must be placed between accesses performed in
* expression evaluations and assignment statements to control the
* orderings of prior versus subsequent accesses appearing in program
* order. These methods also return their arguments to simplify
* correct usage in these contexts.
*
*
Usages of ordering methods almost always take one of the forms
* illustrated in the examples below. These idioms arrange some of
* the ordering properties associated with {@code volatile} and
* related language-based constructions, but without other
* compile-time and runtime benefits that make language-based
* constructions far better choices when they are applicable. Usages
* should be restricted to the control of strictly internal
* implementation matters inside a class or package, and must either
* avoid or document any consequent violations of ordering or safety
* properties expected by users of a class employing them.
*
*
Reachability. Method {@code reachabilityFence}
* establishes an ordering for strong reachability (as defined in the
* {@link java.lang.ref} package specification) with respect to
* garbage collection. Method {@code reachabilityFence} differs from
* the others in that it controls relations that are otherwise only
* implicit in a program -- the reachability conditions triggering
* garbage collection. As illustrated in the sample usages below,
* this method is applicable only when reclamation may have visible
* effects, which is possible for objects with finalizers (see Section
* 12.6 of the Java Language Specification) that are implemented in
* ways that rely on ordering control for correctness.
*
*
Sample Usages
*
*
Safe publication. With care, method {@code orderWrites}
* may be used to obtain the memory safety effects of {@code final}
* for a field that cannot be declared as {@code final}, because its
* primary initialization cannot be performed in a constructor, in
* turn because it is used in a framework requiring that all classes
* have a no-argument constructor; as in:
*
*
* class WidgetHolder {
* private Widget widget;
* public WidgetHolder() {}
* public static WidgetHolder newWidgetHolder(Params params) {
* WidgetHolder h = new WidgetHolder();
* h.widget = new Widget(params);
* return Fences.orderWrites(h);
* }
* }
*
*
* Here, the invocation of {@code orderWrites} ensures that the
* effects of the widget assignment are ordered before those of any
* (unknown) subsequent stores of {@code h} in other variables that
* make {@code h} available for use by other objects. Initialization
* sequences using {@code orderWrites} require more care than those
* involving {@code final} fields. When {@code final} is not used,
* compilers cannot help you to ensure that the field is set correctly
* across all usages. You must fully initialize objects
* before the {@code orderWrites} invocation that makes
* references to them safe to assign to accessible variables. Further,
* initialization sequences must not internally "leak" the reference
* by using it as an argument to a callback method or adding it to a
* static data structure. If less constrained usages were required,
* it may be possible to cope using more extensive sets of fences, or
* as a normally better choice, using synchronization (locking).
* Conversely, if it were possible to do so, the best option would be
* to rewrite class {@code WidgetHolder} to use {@code final}.
*
* An alternative approach is to place similar mechanics in the
* (sole) method that makes such objects available for use by others.
* Here is a stripped-down example illustrating the essentials. In
* practice, among other changes, you would use access methods instead
* of a public field.
*
*
* class AnotherWidgetHolder {
* public Widget widget;
* void publish(Widget w) {
* this.widget = Fences.orderWrites(w);
* }
* // ...
* }
*
*
* In this case, the {@code orderWrites} invocation occurs before the
* store making the object available. Correctness again relies on
* ensuring that there are no leaks prior to invoking this method, and
* that it really is the only means of accessing the
* published object. This approach is not often applicable --
* normally you would publish objects using a thread-safe collection
* that itself guarantees the expected ordering relations. However, it
* may come into play in the construction of such classes themselves.
*
* Safely updating fields. Outside of the initialization
* idioms illustrated above, Fence methods ordering writes must be
* paired with those ordering reads. To illustrate, suppose class
* {@code c} contains an accessible variable {@code data} that should
* have been declared as {@code volatile} but wasn't:
*
*
* class C {
* Object data; // need volatile access but not volatile
* // ...
* }
*
* class App {
* Object getData(C c) {
* return Fences.orderReads(c).data;
* }
*
* void setData(C c) {
* Object newValue = ...;
* c.data = Fences.orderWrites(newValue);
* Fences.orderAccesses(c);
* }
* // ...
* }
*
*
* Method {@code getData} provides an emulation of {@code volatile}
* reads of (non-long/double) fields by ensuring that the read of
* {@code c} obtained as an argument is ordered before subsequent
* reads using this reference, and then performs the read of its
* field. Method {@code setData} provides an emulation of volatile
* writes, ensuring that all other relevant writes have completed,
* then performing the assignment, and then ensuring that the write is
* ordered before any other access. These techniques may apply even
* when fields are not directly accessible, in which case calls to
* fence methods would surround calls to methods such as {@code
* c.getData()}. However, these techniques cannot be applied to
* {@code long} or {@code double} fields because reads and writes of
* fields of these types are not guaranteed to be
* atomic. Additionally, correctness may require that all accesses of
* such data use these kinds of wrapper methods, which you would need
* to manually ensure.
*
* More generally, Fence methods can be used in this way to achieve
* the safety properties of {@code volatile}. However their use does
* not necessarily guarantee the full sequential consistency
* properties specified in the Java Language Specification chapter 17
* for programs using {@code volatile}. In particular, emulation using
* Fence methods is not guaranteed to maintain the property that
* {@code volatile} operations performed by different threads are
* observed in the same order by all observer threads.
*
*
Acquire/Release management of thread safe objects. It may
* be possible to use weaker conventions for volatile-like variables
* when they are used to keep track of objects that fully manage their
* own thread-safety and synchronization. Here, an acquiring read
* operation remains the same as a volatile-read, but a releasing
* write differs by virtue of not itself ensuring an ordering of its
* write with subsequent reads, because the required effects are
* already ensured by the referenced objects.
* For example:
*
*
* class Item {
* synchronized f(); // ALL methods are synchronized
* // ...
* }
*
* class ItemHolder {
* private Item item;
* Item acquireItem() {
* return Fences.orderReads(item);
* }
*
* void releaseItem(Item x) {
* item = Fences.orderWrites(x);
* }
*
* // ...
* }
*
*
* Because this construction avoids use of {@code orderAccesses},
* which is typically more costly than the other fence methods, it may
* result in better performance than using {@code volatile} or its
* emulation. However, as is the case with most applications of fence
* methods, correctness relies on the usage context -- here, the
* thread safety of {@code Item}, as well as the lack of need for full
* volatile semantics inside this class itself. However, the second
* concern means that it can be difficult to extend the {@code
* ItemHolder} class in this example to be more useful.
*
* Avoiding premature finalization. Finalization may occur
* whenever a Java Virtual Machine detects that no reference to an
* object will ever be stored in the heap: A garbage collector may
* reclaim an object even if the fields of that object are still in
* use, so long as the object has otherwise become unreachable. This
* may have surprising and undesirable effects in cases such as the
* following example in which the bookkeeping associated with a class
* is managed through array indices. Here, method {@code action}
* uses a {@code reachabilityFence} to ensure that the Resource
* object is not reclaimed before bookkeeping on an associated
* ExternalResource has been performed; in particular here, to ensure
* that the array slot holding the ExternalResource is not nulled out
* in method {@link Object#finalize}, which may otherwise run
* concurrently.
*
*
* class Resource {
* private static ExternalResource[] externalResourceArray = ...
*
* int myIndex;
* Resource(...) {
* myIndex = ...
* externalResourceArray[myIndex] = ...;
* ...
* }
* protected void finalize() {
* externalResourceArray[myIndex] = null;
* ...
* }
* public void action() {
* try {
* // ...
* int i = myIndex;
* Resource.update(externalResourceArray[i]);
* } finally {
* Fences.reachabilityFence(this);
* }
* }
* private static void update(ExternalResource ext) {
* ext.status = ...;
* }
* }
*
*
* Here, the call to {@code reachabilityFence} is unintuitively
* placed after the call to {@code update}, to ensure that
* the array slot is not nulled out by {@link Object#finalize} before
* the update, even if the call to {@code action} was the last use of
* this object. This might be the case if for example a usage in a
* user program had the form {@code new Resource().action();} which
* retains no other reference to this Resource. While probably
* overkill here, {@code reachabilityFence} is placed in a {@code
* finally} block to ensure that it is invoked across all paths in the
* method. In a method with more complex control paths, you might
* need further precautions to ensure that {@code reachabilityFence}
* is encountered along all of them.
*
* It is sometimes possible to better encapsulate use of
* {@code reachabilityFence}. Continuing the above example, if it
* were OK for the call to method update to proceed even if the
* finalizer had already executed (nulling out slot), then you could
* localize use of {@code reachabilityFence}:
*
*
* public void action2() {
* // ...
* Resource.update(getExternalResource());
* }
* private ExternalResource getExternalResource() {
* ExternalResource ext = externalResourceArray[myIndex];
* Fences.reachabilityFence(this);
* return ext;
* }
*
*
* Method {@code reachabilityFence} is not required in
* constructions that themselves ensure reachability. For example,
* because objects that are locked cannot in general be reclaimed, it
* would suffice if all accesses of the object, in all methods of
* class Resource (including {@code finalize}) were enclosed in {@code
* synchronized (this)} blocks. (Further, such blocks must not include
* infinite loops, or themselves be unreachable, which fall into the
* corner case exceptions to the "in general" disclaimer.) However,
* method {@code reachabilityFence} remains a better option in cases
* where this approach is not as efficient, desirable, or possible;
* for example because it would encounter deadlock.
*
*
Formal Properties.
*
*
Using the terminology of The Java Language Specification chapter
* 17, the rules governing the semantics of the methods of this class
* are as follows:
*
*
The following is still under construction.
*
*
*
* - [Definitions]
*
-
*
*
* - Define sequenced(a, b) to be true if a
* occurs before b in program order.
*
*
- Define accesses(a, p) to be true if
* a is a read or write of a field (or if an array, an
* element) of the object referenced by p.
*
*
- Define deeplyAccesses(a, p) to be true if either
* accesses(a, p) or deeplyAccesses(a, q) where
* q is the value seen by some read r
* such that accesses(r, p).
*
*
*
*
- [Matching]
*
- Given:
*
*
*
* - p, a reference to an object
*
*
- wf, an invocation of {@code orderWrites(p)} or
* {@code orderAccesses(p)}
*
*
- w, a write of value p
*
*
- rf, an invocation of {@code orderReads(p)} or
* {@code orderAccesses(p)}
*
*
- r, a read returning value p
*
*
* If:
*
* - sequenced(wf, w)
*
- read r sees write w
*
- sequenced(r, rf)
*
* Then:
*
*
* - wf happens-before rf
*
*
- wf precedes rf in the
* synchronization order
*
*
- If (r1, w1) and (r2,
* w2) are two pairs of reads and writes, both
* respectively satisfying the above conditions for p,
* and sequenced(r1, r2) then it is not the case that w2
* happens-before w1.
*
*
*
*
- [Initial Reads]
*
- Given:
*
*
*
* - p, a reference to an object
*
*
- a, an access where deeplyAccesses(a, p)
*
*
- wf, an invocation of {@code orderWrites(p)} or
* {@code orderAccesses(p)}
*
*
- w, a write of value p
*
*
- r, a read returning value p
*
*
- b, an access where accesses(b, p)
*
*
* If:
*
* - sequenced(a, wf);
*
- sequenced(wf, w)
*
- read r sees write w, and
* r is the first read by some thread
* t that sees value p
*
- sequenced(r, b)
*
* Then:
*
* - the effects of b are constrained
* by the relation a happens-before b.
*
*
*
- [orderAccesses]
*
- Given:
*
*
* - p, a reference to an object
*
- f, an invocation of {@code orderAccesses(p)}
*
* If:
*
* - sequenced(f, w)
*
*
* Then:
*
*
*
* - f is an element of the synchronization order.
*
*
*
*
- [Reachability]
*
- Given:
*
*
*
* - p, a reference to an object
*
*
- f, an invocation of {@code reachabilityFence(p)}
*
*
- a, an access where accesses(a, p)
*
*
- b, an action (by a garbage collector) taking
* the form of an invocation of {@code
* p.finalize()} or of enqueuing any {@link
* java.lang.ref.Reference} constructed with argument p
*
*
*
* If:
*
* - sequenced(a, f)
*
*
* Then:
*
*
*
* - a happens-before b.
*
*
*
*
*
* @since 1.7
* @author Doug Lea
*/
@SuppressWarnings("UnusedDeclaration")
public class Fences {
private Fences() {} // Non-instantiable
/*
* The methods of this class are intended to be intrinisified by a
* JVM. However, we provide correct but inefficient Java-level
* code that simply reads and writes a static volatile
* variable. Without JVM support, the consistency effects are
* stronger than necessary, and the memory contention effects can
* be a serious performance issue.
*/
private static volatile int theVolatile;
/**
* Informally: Ensures that a read of the given reference prior to
* the invocation of this method occurs before a subsequent use of
* the given reference with the effect of reading or writing a
* field (or if an array, element) of the referenced object. The
* use of this method is sensible only when paired with other
* invocations of {@link #orderWrites} and/or {@link
* #orderAccesses} for the given reference. For details, see the
* class documentation for this class.
*
* @param ref the reference. If null, this method has no effect.
* @return the given ref, to simplify usage
*/
public static T orderReads(final T ref) {
final int ignore = theVolatile;
return ref;
}
/**
* Informally: Ensures that a use of the given reference with the
* effect of reading or writing a field (or if an array, element)
* of the referenced object, prior to the invocation of this
* method occur before a subsequent write of the reference. For
* details, see the class documentation for this class.
*
* @param ref the reference. If null, this method has no effect.
* @return the given ref, to simplify usage
*/
public static T orderWrites(final T ref) {
theVolatile = 0;
return ref;
}
/**
* Informally: Ensures that accesses (reads or writes) using the
* given reference prior to the invocation of this method occur
* before subsequent accesses. For details, see the class
* documentation for this class.
*
* @param ref the reference. If null, this method has no effect.
* @return the given ref, to simplify usage
*/
public static T orderAccesses(final T ref) {
theVolatile = 0;
return ref;
}
/**
* Ensures that the object referenced by the given reference
* remains strongly reachable (as defined in the {@link
* java.lang.ref} package documentation), regardless of any prior
* actions of the program that might otherwise cause the object to
* become unreachable; thus, the referenced object is not
* reclaimable by garbage collection at least until after the
* invocation of this method. Invocation of this method does not
* itself initiate garbage collection or finalization.
*
* See the class-level documentation for further explanation
* and usage examples.
*
* @param ref the reference. If null, this method has no effect.
*/
public static void reachabilityFence(final Object ref) {
if (ref != null) {
synchronized (ref) {}
}
}
}