`

Usage of java.util.concurrent.atomic

    博客分类:
  • Java
阅读更多

First let's see what does Atomic mean?(see http://www.techopedia.com/definition/16246/atomic-java)

 

Atomic is a toolkit of variable java.util.concurrent.atomic package classes, which assist in writing lock and wait-free algorithms with the Java language. An algorithm requiring only partial threads for constant progress is lock-free. In a wait-free algorithm, all threads make progress continuously, even in cases of thread failure or delay. Lock and wait-free algorithms are also known as nonblocking algorithms. Nonblocking algorithms are used for process and thread scheduling at the operating system and Java virtual machine levels.

 

All java.util.concurrent.atomic package classes have the "atomic" prefix in their names. There are different types of atomic variables available in the java.util.concurrent.atomic package, including:

  • AtomicBoolean
  • AtomicInteger
  • AtomicIntegerArray
  • AtomicIntegerFieldUpdater
  • AtomicLong
  • AtomicLongArray
  • AtomicLongFieldUpdater
  • AtomicReference

1.AtomicBoolean

An AtomicBoolean is used in applications such as atomically updated flags, and cannot be used as a replacement for a Boolean. (jdk doc)

When multiple threads need to check and change the boolean. For example:

 boolean initialized;
 void init(){
  if (!initialized) {
     initialize();
     initialized = true;
  }
 }

 This is not thread safe, we can add synchronized to make it thread safe like following way

 

	boolean initialized;
	synchronized void init(){
		if (!initialized) {
	  	 initialize();
	   	initialized = true;
		}
	}

 Synchronized is the heavy lock known as the thread blocking algorithm. There is better ways to make it work not using the lock. AtomicBoolean is the thread safe class which provide the thread safe method . Actually it use the CAS (compare and set) operate. CAS is generally much faster than locking as it is the nonblocking algorithms. See the code below

AtomicBoolean initialized;
if (initialized.compareAndSet(false, true)) {
    initialize();
}

 it use the mehtod compareAndSet from Unsafe.class

    public final boolean compareAndSet(boolean expect, boolean update) {
        int e = expect ? 1 : 0;
        int u = update ? 1 : 0;
        return unsafe.compareAndSwapInt(this, valueOffset, e, u);
    }

 Unsafe.class

    /**
     * Atomically update Java variable to <tt>x</tt> if it is currently
     * holding <tt>expected</tt>.
     * @return <tt>true</tt> if successful
     */
    public final native boolean compareAndSwapInt(Object o, long offset,
                                                  int expected,
                                                  int x);

 Actually it first get the address from the memoery and then update the value by java reflect. We can see that compareAndSwapInt is the native method .

    static {
      try {
        valueOffset = unsafe.objectFieldOffset
            (AtomicBoolean.class.getDeclaredField("value"));
      } catch (Exception ex) { throw new Error(ex); }
    }

    private volatile int value;

 

2. AtomicInteger

An AtomicIntegeris used in applications such as atomically incremented counters, and cannot be used as a replacement for an Integer. However, this class does extend Number to allow uniform access by tools and utilities that deal with numerically-based classes.(jdk doc)

 

There are two main uses of AtomicInteger

 

  • As an atomic counter (incrementAndGet(), etc) that can be used by many threads concurrently
  • As a primitive that supports compare-and-swap instruction (compareAndSet()) to implement non-blocking algorithms.

private volatile int counter;

public int getNextUniqueIndex() {
    return counter++; // Not atomic, multiple threads could get the same result
}

 

private AtomicInteger counter;

public int getNextUniqueIndex() {
    return counter.getAndIncrement();
}

 

    /**
     * Atomically increments by one the current value.
     *
     * @return the previous value
     */
    public final int getAndIncrement() {
        for (;;) {
            int current = get();
            int next = current + 1;
            if (compareAndSet(current, next))
                return current;
        }
    }

 

3. AtomicReference

An object reference that may be updated atomically. See the java.util.concurrent.atomic package specification for description of the properties of atomic variables. (jdk doc)

 

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: (from http://www.javamex.com/tutorials/synchronization_concurrency_7_atomic_reference.shtml)

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; }
}

 

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));
}

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics