malaikuangren

What is the purpose or drive to build thing like (xxx),How can it achieve the original goal of design?
The Atomic classes in Java 5: AtomicInteger and AtomicLong,AtomicReference etc.

The AtomicInteger class has a number of uses, but one is a drop-in replacement for an atomic counter. Before Java 5, we had to write classes with access to the counter variable insynchronized blocks or methods, or else use a volatile variable which is a lighter form of synchronization but with the risk that some updates could be missed if they happen concurrently. An AtomicInteger can be used as a drop-in replacement that provides the best of both worlds:

public class Counter {
  private AtomicInteger count = new AtomicInteger(0);
  public void incrementCount() {
    count.incrementAndGet();
  }
  public int getCount() {
    return count.get();}
}

The significant feature of AtomicInteger which we exploit is the call to incrementAndGet(). This method wraps round a machine instruction (or instructions) similar to CAS which will read, increment and set the underlying value in memory as a 'locked together' (atomic) action(it means only one thread can access this compound actions. so we can observe it is thread safety). Notice that this method returns the new incremented value, although we ignore it. On the other hand, if we were using AtomicInteger to do something like provide the next key to store in a database, we would probably want to take notice of the return value.

Unsurprisingly, AtomicLong provides similar atomic access to an underlying long variable.

On this page, we look at AtomicReference classes that can be useful when you want to couple more than piece of data together and access them atomically.

Note that the classes on this page are probably less used than AtomicInteger and AtomicLong. On the following page, we will discuss a much more important part of the Java concurrency framework, namely the ConcurrentHashMap class.

AtomicReference

The AtomicReference class provides a way to atomically read and set an object reference. It is generally used to tie together more than one atomically accessed variable by wrapping them in an immutable object instance (that is, one whose fields are final).

Suppose, for example, that in a web server application, we want to count the number of page accesses and also the number of accesses that failed due to an error. We can do this by creating a class to encapsulate the current statistics, and then create and update an AtomicReference to an instance of this class:

public class AccessStatistics {
  private final int noPages, noErrors;
  public AccessStatistics(int noPages, int noErrors) {
    this.noPages = noPages;
    this.noErrors = noErrors;
  }
  public int getNoPages() { return noPages; }
  public int getNoErrors() { return noErrors; }
}

 

Now, to update the statistics, we can use a method such as the following:

private AtomicReference<AccessStatistics> stats =
  new AtomicReference<AccessStatistics>(new AccessStatistics(0, 0));

public void incrementPageCount(boolean wasError) {
  AccessStatistics prev, newValue;
  do {
    prev = stats.get();
    int noPages = prev.getNoPages() + 1;
    int noErrors = prev.getNoErrors;
    if (wasError) {
      noErrors++;
    }
    newValue = new AccessStatistics(noPages, noErrors);
  } while (!stats.compareAndSet(prev, newValue));
}

 

Atomic references (and atomic classes in general) have the same memory semantics as volatile variables. So when the reference to the new AccessStatistics is set to theAtomicReference, at that moment, the JVM must ensure that the variables set during the constructor are visible to other threads. In other words, Any write to volatile or atomic references variables  can be observed by the other threads.it isn't strictly necessary in this case to make the fields on AccessStatistics final. Nonetheless, it's good practice to mark fields on immutable classes as final, and we do so here.

When to use AtomicReference

Atomic reference should be used in a setting where you need to do simple atomic (i.e., thread safe, non-trivial) operations on a reference, for which monitor-based synchronization is not appropriate. Suppose you want to check to see if a specific field only if the state of the object remains as you last checked:

AtomicReference<Object> cache =newAtomicReference<Object>();

Object cachedValue =newObject();
cache.set(cachedValue);

//... time passes ...
Object cachedValueToUpdate = cache.get();
//... do some work to transform cachedValueToUpdate into a new version
Object newValue = someFunctionOfOld(cachedValueToUpdate);
boolean success = cache.compareAndSet(cachedValue,cachedValueToUpdate);
 

Because of the atomic reference semantics, you can do this even if the cache object is shared amongst threads, without using synchronized. In general, you're better off using synchronizers or thejava.util.concurrent framework rather than bare Atomic* unless you know what you're doing.

Two excellent dead-tree references which will introduce you to this topic: Herlihy's excellent Art of Multiprocessor Programming and Java Concurrency in Practice.

Note that (I don't know if this has always been true) reference assignment (i.e., =) is itself atomic (for everything except perhaps double and long) without explicitly using an Atomic*. See the JLS 3ed, Section 17.7,

Other uses for AtomicReference

The AtomicReference class can also be useful in cases where you have a structure which is basically read-only but which you very occasionally want to update. On the occasional update, you can replace the old copy with a brand new copy.

 

Constructor Detail

AtomicReference

public AtomicReference(V initialValue)
Creates a new AtomicReference with the given initial value.

 

Parameters:
initialValue - the initial value

AtomicReference

public AtomicReference()
Creates a new AtomicReference with null initial value.

 

Method Detail

get

public final V get()
Gets the current value.

 

Returns:
the current value

set

public final void set(V newValue)
Sets to the given value.

 

Parameters:
newValue - the new value

lazySet

public final void lazySet(V newValue)
Eventually sets to the given value.

 

Parameters:
newValue - the new value
Since:
1.6

compareAndSet

public final boolean compareAndSet(V expect,
                                   V update)
Atomically sets the value to the given updated value if the current value == the expected value.

 

Parameters:
expect - the expected value
update - the new value
Returns:
true if successful. False return indicates that the actual value was not equal to the expected value.

weakCompareAndSet

public final boolean weakCompareAndSet(V expect,
                                       V update)
Atomically sets the value to the given updated value if the current value == the expected value.

May fail spuriously and does not provide ordering guarantees, so is only rarely an appropriate alternative to compareAndSet.

 

Parameters:
expect - the expected value
update - the new value
Returns:
true if successful.

getAndSet

public final V getAndSet(V newValue)
Atomically sets to the given value and returns the old value.

 

Parameters:
newValue - the new value
Returns:
the previous value

toString

public String toString()
Returns the String representation of the current value.

 

Overrides:
toString in class Object
Returns:
the String representation of the current value.

 

 

 

posted on 2012-07-15 17:23  malaikuangren  阅读(508)  评论(0编辑  收藏  举报