CAS非左塞同步算法

在java并发编程里要实现原子操作,大家都会想到同步(synchronize),这种同步会使线程左塞,在性能上不是很满意。基于CAS(Compare And Set) 可以实现非左塞同步算法。

何为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

非阻塞的计数器

使用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 赋值给自己,如果执行失败,说明有其他线程修改了值,只要重新循环执行一次操作,直到成功为止。 

非阻塞的简单链表

使用AtomicReference实现一个简单的链表操作(add),总体类结构和普通的链表差不多。


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"问题)。


参考资料

《java并发编程实践》






你可能感兴趣的:(set,cas,compare,原子操作,and,非左塞同步)