无锁编程,即不使用锁的状况下实现多线程之间的变量同步,也就是在没有线程被阻塞的状况下实现变量的同步,因此也叫非阻塞同步(Non-blocking Synchronization)。html
实现非阻塞同步的方案称为“无锁编程算法”( Non-blocking algorithm)。算法
lock-free是目前最多见的无锁编程的实现级别(一共三种级别):编程
使用lock实现线程同步有不少缺点:安全
* 产生竞争时,线程被阻塞等待,没法作到线程实时响应。数据结构
* dead lock。多线程
* live lock。并发
* 优先级翻转。ide
* 使用不当,形成性能降低。oop
是最理想的模式,整个操做保证每一个线程在有限步骤下完成。性能
保证系统级吞吐(system-wide throughput)以及无线程饥饿。
截止2011年,没有多少具体的实现。即便实现了,也须要依赖于具体CPU。
容许个别线程饥饿,但保证系统级吞吐。
确保至少有一个线程可以继续执行。
wait-free的算法一定也是lock-free的。
在任什么时候间点,一个线程被隔离为一个事务进行执行(其余线程suspended),而且在有限步骤内完成。
在执行过程当中,一旦发现数据被修改(采用时间戳、版本号),则回滚。
也叫作乐观锁,即乐观并发控制(OOC)。
事务的过程是:1读取,并写时间戳;2准备写入,版本校验;3校验经过则写入,校验不经过,则回滚。
CAS( compare and swap) 原子操做,用来实现多线程下的变量同步。
保证了若是须要更新的地址没有被其余进程(线程)改动过,那么它能够安全的写入。
而这也是咱们对于某个数据或者数据结构加锁要保护的内容,保证读写的一致性,不出现dirty data。
CAS原语有三个参数:
算法逻辑:
int compare_and_swap (int* reg, int oldval, int newval) { ATOMIC(); int old_reg_val = *reg; if (old_reg_val == oldval) *reg = newval; END_ATOMIC(); return old_reg_val; }
可在循环中不断执行CAS,若是共享变量没有改变,那么swap,在当前环境中写入,不然继续do-while的Retry-Loop。
ABA问题最容易发生在lock free算法中的,地址被重用的状况。
无锁至关于“锁”的粒度变小了,主要是“锁”HEAD和TAIL这两个关键资源。而不是整个数据结构。
thread1意图对val=1进行操做变成2,cas(*val,1,2)。
thread1先读取val=1;thread1被抢占(preempted),让thread2运行。
thread2 修改val=3,又修改回1。
thread1继续执行,发现指望值与“原值”(其实被修改过了)相同,完成CAS操做。
使用CAS会形成ABA问题,特别是在使用指针操做一些并发数据结构时。
解决方案
ABAʹ:添加额外的标记用来指示是否被修改。
# Java demo AtomicInteger atom = new AtomicInteger(1); boolean r = atom.compareAndSet(1, 2); # C# demo int i=1; Interlocked.Increment(ref i);