CAS非左塞同步算法

在java併發編程裏要實現原子操做,你們都會想到同步(synchronize),這種同步會使線程左塞,在性能上不是很滿意。基於CAS(Compare And Set) 能夠實現非左塞同步算法。 java

何爲cas? 算法

compare-and-swap (CAS) is an atomic instruction used in multithreading to achieve synchronization

簡單來講就是原子操做,系統支不支持CAS還要看cpu,如今幾乎全部的CPU指令都支持CAS的原子操做,X86下對應的是 CMPXCHG 彙編指令。cas指令須要三個操做數,非別是內存位置(V),舊值預期值(A)和新值。cas指令執行時,當且僅當V符合舊預期值A是,處理器用新的值B更新V的值,不然不執行更新。 編程

jdk1.5爲咱們提供java.util.concurrent併發包,提供很方便的原子操做類,底層實現由sun.misc.Unsaft類裏的compareAndWapInt和compareAndLong等幾個方法封裝調用,注意sun.misc.Unsaft是非標準的java api api

非阻塞的計數器 多線程

使用AtomicInteger的compareAndSet方法,很是簡單實現非左塞的計數器,代碼比用同步塊實現多線程的計數器簡單的多。 併發


public class NonblockingCounter {
    private AtomicInteger value;
    public int getValue() {
        return value.get();
    }
    public int increment() {
        int v;
        do {
            v = value.get();
        while (!value.compareAndSet(v, v + 1));
        return v + 1;
    }
}

compareAndSet在一個死循環中,不斷嘗試將一個比當前值大1 賦值給本身,若是執行失敗,說明有其餘線程修改了值,只要從新循環執行一次操做,直到成功爲止。  性能

非阻塞的簡單鏈表 this

使用AtomicReference實現一個簡單的鏈表操做(add),整體類結構和普通的鏈表差很少。 atom


public class ConcurrentLinked<E> {

	private AtomicReference<Node<E>> first = new AtomicReference<Node<E>>();

	public boolean add(E e) {
		

		Node<E> n = new Node<E>(e);

		while (first.get() == null && first.compareAndSet(null, n)) {
			return true;
		}

		for (;;) {
			Node<E> insertNode = findInsertionPlace();

			if (insertNode.next.compareAndSet(null, n)) {
				break;
			}
		}

		return true;
	}


	public E getLast() {
		Node<E> a = getFirstNode();

		if (a == null)
			return null;

		while (a.next.get() != null) { // 找插入位置
			a = a.next.get();
		}
		return a.item;
	}

	private Node<E> getFirstNode() {
		return this.first.get();
	}

	private Node<E> findInsertionPlace() {
		Node<E> a = getFirstNode();

		while (a.next.get() != null) { // 找插入位置
			a = a.next.get();
		}

		return a;
	}

	private static class Node<E> {

		E item;

		AtomicReference<Node<E>> next = new AtomicReference<Node<E>>();

		public Node(E item) {
			this.item = item;
		}
	}


}




cas看似很完美,可是不是全部的原子操做場景都適合,好比,多個變量同步原子更新。使用cas的地方,通常會把compareAndSet放到一個無限的循環中,在線程競爭比較激烈的狀況下,cpu消耗比較嚴重的。另外,cas自己有一個邏輯漏洞(俗稱"ABA"問題)。 spa


參考資料

《java併發編程實踐》

相關文章
相關標籤/搜索