在看下debug下面代碼的時候發現了sun.misc.Unsafe這個類,居然不是javaSE的一部分,說可能會在將來的版本刪除掉,不過現在不是還有麼,那就看看吧
源碼地址:http://www.docjar.com/docs/api/sun/misc/Unsafe.html
附一篇文章:http://mishadoff.com/blog/java-magic-part-4-sun-dot-misc-dot-unsafe/
這篇文章的結論是:Although, Unsafe
has a bunch of useful applications, never use it.
=====================================華麗的分割線==================================
轉載地址:http://blog.csdn.net/hong0220/article/details/38958121
一個沒有併發控制的計數器:
- public class Counter implements Runnable {
- private static int count;
- public void run() {
- System.out.println(Thread.currentThread().getName()
- + ":" + (++count));
- }
- public static void main(String[] args){
- Counter counter = new Counter();
- Thread t1 = new Thread(counter);
- Thread t2 = new Thread(counter);
- Thread t3 = new Thread(counter);
- Thread t4 = new Thread(counter);
- t1.start();
- t2.start();
- t3.start();
- t4.start();
- }
- }
有時運行正常,但是偶爾會出現如下運行結果:
- Thread-1:2
- Thread-0:1
- Thread-2:3
- Thread-3:3
這顯然和預期結果不太一樣,先用javap -verbose命令分析一下這個類,在字節碼層面上,++count等價於虛擬機順次執行如下5條字節碼指令(不考慮運行期的優化)
- getstatic 獲取指定類的靜態域,並將其值壓入棧頂
- iconst_1 將int型1推送至棧頂
- iadd 將棧頂兩int型數值相加並將結果壓入棧頂
- dup 複製棧頂數值並將複製值壓入棧頂
- putstatic 爲指定類的靜態域賦值
當Thread-3線程執行getstatic指令時,Thread-2線程還未執行至iadd指令,故Thread-3線程獲取的初始靜態域count的值和Thread-2線程一樣,都爲2
本質原因就是++count雖然只是一行代碼,但這一過程並非原子操作
要保證這種類型的原子操作,可以使用java.util.concurrent.atomic包下的類
- 軟件包 java.util.concurrent.atomic
- 類的小工具包,支持在單個變量上解除鎖的線程安全編程。
示例如下:
- public class Counter implements Runnable {
- private final AtomicInteger count = new AtomicInteger(0);
- public void run() {
- System.out.println(Thread.currentThread().getName()
- + ":" + count.incrementAndGet());
- }
- public static void main(String[] args){
- Counter counter = new Counter();
- Thread t1 = new Thread(counter);
- Thread t2 = new Thread(counter);
- Thread t3 = new Thread(counter);
- Thread t4 = new Thread(counter);
- t1.start();
- t2.start();
- t3.start();
- t4.start();
- }
- }
看看源代碼中究竟是如何實現的
- private volatile int value;
- public AtomicInteger(int initialValue) {
- value = initialValue;
- }
- public final int incrementAndGet() {
- for (;;) {
- int current = get();
- int next = current + 1;
- if (compareAndSet(current, next))
- return next;
- }
- }
- /**
- * Atomically sets the value to the given updated value
- * if the current value {@code ==} the expected value.
- *
- * @param expect the expected value
- * @param update the new value
- * @return true if successful. False return indicates that
- * the actual value was not equal to the expected value.
- */
- public final boolean compareAndSet(int expect, int update) {
- return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
- }
- public final int get() {
- return value;
- }
是不是和樂觀鎖很像,如果結果符合預期結果,就將結果返回,否則不斷進行重試,並沒有進行同步,兼顧了安全性和性能
java.util.concurrent.atomic包下還有很多類,使用這些類可以保證對這些類的諸如“獲取-更新”操作是原子性的,從而避發生競態條件
- AtomicBoolean 可以用原子方式更新的 boolean 值。
- AtomicInteger 可以用原子方式更新的 int 值。
- AtomicIntegerArray 可以用原子方式更新其元素的 int 數組。
- AtomicIntegerFieldUpdater<T> 基於反射的實用工具,可以對指定類的指定 volatile int 字段進行原子更新。
- AtomicLong 可以用原子方式更新的 long 值。
- AtomicLongArray 可以用原子方式更新其元素的 long 數組。
- AtomicLongFieldUpdater<T> 基於反射的實用工具,可以對指定類的指定 volatile long 字段進行原子更新。
- AtomicMarkableReference<V> AtomicMarkableReference 維護帶有標記位的對象引用,可以原子方式對其進行更新。
- AtomicReference<V> 可以用原子方式更新的對象引用。
- AtomicReferenceArray<E> 可以用原子方式更新其元素的對象引用數組。
- AtomicReferenceFieldUpdater<T,V> 基於反射的實用工具,可以對指定類的指定 volatile 字段進行原子更新。
- AtomicStampedReference<V> AtomicStampedReference 維護帶有整數“標誌”的對象引用,可以用原子方式對其進行更新。