java并发编程学习13--Atomic数据结构简介

【介绍

JAVA 中无锁的线程安全整数 AtomicInteger,一个提供原子操做的Integer的类。在Java语言中,++i和i++操做并非线程安全的,在使用的时候,不可避免的会用到synchronized关键字。而AtomicInteger则经过一种线程安全的加减操做接口。AtomicInteger为何可以达到多而不乱,处理高并发应付自如呢?这是由硬件提供原子操做指令实现的,这里面用到了一种并发技术:CAS。在非激烈竞争的状况下,开销更小,速度更快。
Java.util.concurrent中实现的原子操做类包括:java

AtomicBoolean、AtomicInteger、AtomicIntegerArray、AtomicLong、AtomicReference、AtomicReferenceArray。

【核心:基于CAS的乐观锁实现

1.悲观锁与乐观锁:程序员

- 悲观锁(Pessimistic Lock), 顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,因此每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁。传统的关系型数据库里边就用到了不少这种锁机制,好比行锁,表锁等,读锁,写锁等,都是在作操做以前先上锁。
 - 乐观锁(Optimistic Lock), 顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,因此不会上锁,可是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可使用版本号等机制。乐观锁适用于多读的应用类型,这样能够提升吞吐量,像数据库若是提供相似于write_condition机制的其实都是提供的乐观锁。

两种锁各有优缺点,不可认为一种好于另外一种,像乐观锁适用于写比较少的状况下,即冲突真的不多发生的时候,这样能够省去了锁的开销,加大了系统的整个吞吐量。但若是常常产生冲突,上层应用会不断的进行retry,这样反却是下降了性能,因此这种状况下用悲观锁就比较合适。数据库

2.CAS:安全

CAS就是Compare and Swap的意思,比较并操做。不少的cpu直接支持CAS指令。CAS是项乐观锁技术,当多个线程尝试使用CAS同时更新同一个变量时,只有其中一个线程能更新变量的值,而其它线程都失败,失败的线程并不会被挂起,而是被告知此次竞争中失败,并能够再次尝试。CAS有3个操做数,内存值V,旧的预期值A,要修改的新值B。当且仅当预期值A和内存值V相同时,将内存值V修改成B,不然什么都不作。多线程

private static final Unsafe unsafe = Unsafe.getUnsafe();

【与synchronized与ReentrantLock的比较

  • synchronized:
    在资源竞争不是很激烈的状况下,偶尔会有同步的情形下,synchronized是很合适的。缘由在于,编译程序一般会尽量的进行优化synchronize,另外可读性很是好,无论用没用过5.0多线程包的程序员都能理解。
  • ReentrantLock:
    ReentrantLock提供了多样化的同步,好比有时间限制的同步,能够被Interrupt的同步(synchronized的同步是不能Interrupt的)等。在资源竞争不激烈的情形下,性能稍微比synchronized差点点。可是当同步很是激烈的时候,synchronized的性能一会儿能降低好几十倍。而ReentrantLock确还能维持常态(1.7后synchronized已经优化,性能差距很小)。
  • Atomic:
    和上面的相似,不激烈状况下,性能比synchronized略逊,而激烈的时候,也能维持常态。激烈的时候,Atomic的性能会优于ReentrantLock一倍左右。可是其有一个缺点,就是只能同步一个值,一段代码中只能出现一个Atomic的变量,多于一个同步无效。由于他不能在多个Atomic之间同步。

【例子

package AtomicData;

import java.util.concurrent.atomic.AtomicInteger;

public class Test {

    public static void main(String[] args) throws InterruptedException {
        Test test = new Test();
        MyThread my = new MyThread(test);
        for (int i = 0; i < 500; i++) {
            Thread t = new Thread(my);
            t.start();
        }
        //等待子线程执行完
        Thread.sleep(5000);
        System.out.println(test.number);
    }

    AtomicInteger number = new AtomicInteger(0);
    protected void update() {
        number.getAndAdd(1);
    }
}
class MyThread implements Runnable {

    Test t;

    public MyThread(Test t){
        this.t =t;
    }

    @Override
    public void run() {
        t.update();
    }
}
相关文章
相关标签/搜索