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

【介绍

    JAVA 中无锁的线程安全整数 AtomicInteger,一个提供原子操作的Integer的类。在Java语言中,++i和i++操作并不是线程安全的,在使用的时候,
    不可避免的会用到synchronized关键字。而AtomicInteger则通过一种线程安全的加减操作接口。AtomicInteger为什么能够达到多而不乱,处理高并发应付自如呢?
    这是由硬件提供原子操作指令实现的,这里面用到了一种并发技术:CAS。在非激烈竞争的情况下,开销更小,速度更快。
    Java.util.concurrent中实现的原子操作类包括:
    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();
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值