java并发处理 synchronized volatile ActomicInteger的关系与区别

来源:互联网 发布:淘宝的详情页图片尺寸 编辑:程序博客网 时间:2024/05/18 03:14

   java中的多线程并发问题是一个让人头疼的问题,因为当多个线程访问同一个资源时,由于一段操作非原子性,就会导致可能出现操作到一半的时候,cpu时间片被切换到其它线程里面去,最终再切换回来的时候,该线程之前所获取的资源已经相当于失效了,但是该线程并不知道,会继续使用,最终导致脏数据的产生。当然java为了解决这个问题提出了同步机制,现在分析其中三个易搞混的东西。

  1. synchronized

       这个万人皆知,实际上核心就是保证一段逻辑的原子性,从而不会出现执行到一半cpu被切换到其他线程执行的情况。


 2. volatile

      这个关键字是干嘛的呢?其实也是为解决并发问题提出的一个机制,当一个变量被这个修饰符修饰时,那么对这个变量的更新会及时刷新到内存中。这是什么意思呢?难道变量更新不是直接更新到内存中吗?其实在java内存中,每一个线程都会保存一个变量副本,而真正的变量会保存在主内存中,这样做的目的很明显是回了提高每个线程的运行效率。但这就给多线程安全埋下了隐患,试想如果每一个线程保留一个变量副本,那么一个线程一旦修改了这个变量就无法及时的让其它线程知道。java为了解决这个问题,发明了volatile这个关键字,就是对这个变量的更新会及时刷新到内存中,这样就保证了每个线程取到的值都是最新的,避免了安全问题。

   但这里注意volatile只是保证及时更新,但并不能保证操作的原子性,所以对于类似 i++ 这种操作用volatile是解决不了安全问题的。因为这个操作本身不是原子的,它其实是分为两步: tem = i;  i = temp +1;这就导致如果在中间过程被打断的化,因为temp已经记录下来老值,所以即使用volatile也会导致脏数据的产生。  

    其实用一句话总结: volatile只是保证每次去取都能取到最新的值,但是对于已经保存的老值它是无能为力。


3.AtomicInteger

   那这个又是什么东东呢?存在的意义又是什么呢?实际上根据名字我们就可以大致推断出这是一个保证操作原子性的东东。之前说过加上synchronized就可以保证原子性,但是这种同步锁机制是很耗资源影响效率的,所以我们一般能不用锁就不用锁。而java里面的atomic包就是采用了一种非加锁的机制实现了原子操作的一种方式。那这种高级的东西是什么呢,其实原理也并不复杂,就是CAS,全称compare and swap, 比较再交换。unsafe.compareAndSwapInt(this, valueOffset, expect, update);这实际上是系统底层提供的一个原子操作机制,先比较本地值是否与expect相等,如果相等话就将本地值替换成update,否则不替换。这个操作是原子的。

  这样我们就明白了AtomicInteger中的这个自增方法是如何保证线程安全的了,

        public final int incrementAndGet() {
        for (;;) {
            int current = get();
            int next = current + 1;
            if (compareAndSet(current, next))//只有 本地值=current 的时候才更新本地值,否则一直永真循环下去。
                return next;
        }
    }


 一般AtomicInteger用于多线程下的变量自增自减操作。


好了,大家明白了吗?

0 0
原创粉丝点击