JAVA无锁,乐观锁,悲观锁,并发包内容学习

原子类的CAS和ABA问题

多线程修改一个值,因为线程会从主内容拷贝副本到自己的工作空间所以会导致这个值出现脏数据,并发即保证修改值操作是一个原子操作

采用原子类 AtomicInteger,AtomicLong,AtomicBoolean, 原子类的底层操作是采用CAS操作,而CAS是CPU层面提供的原子操作,

即原子类能保证操作具备原子性(原理:CPU执行CAS操作时会使其他CPU核缓存行数据设置失效,致使同一时间不可能有两个核操作一个数据来保证顺序操作)

然而:

CAS存在ABA问题,对于数字计算ABA不影响结果,但是对于对象,字符串具备不同的意义,关于字符串处理ABA问题JAVA中有

AtomicStampedReference<T>,AtomicMarkableReference<T>来解决

AtomicStampedReference初始化设置对象和版本号,CAS时也加版本号处理,类似数据库的乐观锁

AtomicMarkableReference初始化设置对象和Boolean,CAS时可以判断是否被修改过

 

ReentrantLock,AtomicInteger,Semaphore并发情况实验

多线程操作数据时发生结果和预期不一致的问题

先来一波不安全操作代码:

public class Test implements Runnable{
    private static int count = 1000;
    @Override
    public void run() {
        count--;
        System.out.println(count);
    }

    public static void main(String[] args) {
        ThreadPoolExecutor threadPool =ThreadPoolExecutorUtil.getInstance();
        for (int i = 0; i <1000 ; i++) {
            threadPool.execute(new Test ());
        }
        threadPool.shutdown();
        while (true){
            if(threadPool.isTerminated()){
                System.out.println("count="+count);
                break;
            }
        }
    }
}

最后发现 count不是每次都是=0,而且打印出来的count--打印值有相同的,问题在于count--并不是原子操作,涉及数据在线程工作空间到主内存空间的数据交互,导致出现脏数据

实验1: 我们将上诉代码count加上voliate修饰    private static int voliate count = 1000;

实验结果:和没加是一样的,count结果有时不符合预期,可见voliate不能保证数据操作原子性

 

实验2:我们将上诉代码count改为private static AtomicInteger count = new AtomicInteger(1000);

实验结果:  count结果可预期一致,AtomicInteger可以保证操作原子性

 

实验3:我们加入reentrantLock

 private static int count = 1000;
    private static ReentrantLock lock = new ReentrantLock();

    @Override
    public void run() {
        try {
            lock.lock();
            count--;
            System.out.println(count);
        } finally {
            lock.unlock();
        }
    }

实验结果: 与预期结果一致

 

实验4:加入Semaphore

  private Semaphore semaphore = new Semaphore(10);

    @Override
    public void run() {
        try {
            semaphore.acquire();
            count--;
            System.out.println(count);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            semaphore.release();
        }
    }

实验结果: Semaphore控制并发数=1时是安全的,设置>1时会出现与预期不符数据

 

实验5: synchronized 同步方法不介绍了,count与预期一致

 

多线程下数据安全操作全依赖原子性:

1.单线程实现操作的原子性,线程顺序执行,缺点一个一个处理太慢

2.synchronized/lock 锁住的代码块相当于原子操作,优点:组合操作形成原子操作

3.使用原子类实现,只能对原子值的改变具有原子性

4.volatile只能保证变量线程间,假设需要一个flag在两个线程间使用,未加关键字的时一个线程改了值另一个线程可能不知

static flag =false,应该使用volatile修饰

 

注: CAS属于乐观锁状态,synchronized/lock属于独占锁悲观锁,通常CAS效率比悲观锁高

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值