`
Donald_Draper
  • 浏览: 972209 次
社区版块
存档分类
最新评论

AtomicInteger解析

    博客分类:
  • JUC
阅读更多
Java中Unsafe类详解:http://www.cnblogs.com/mickole/articles/3757278.html
通常情况下,在Java里面,++i或者--i不是线程安全的,这里面有三个独立的操作:
或者变量当前值,为该值+1/-1,然后写回新的值。在没有额外资源可以利用的情况下,只能使用加锁才能保证读-改-写这三个操作时“原子性”的。Doug Lea在未将backport-util-concurrent合并到JSR 166里面来之前,是采用纯Java实现的,于是不可避免的采用了synchronized关键字。
public final synchronized void set(int newValue); 
public final synchronized int getAndSet(int newValue); 
public final synchronized int incrementAndGet(); 

同时在变量上使用了volatile来保证get()的时候不用加锁。
尽管synchronized的代价还是很高的,但是在没有JNI的手段下纯Java语言还是不能实现此操作的。而volatile只能保证变量改变时,对其他线程可以立即看到,因为volatile标注的变量,每次都是从内存中直接读取;同时当多线程修改值是,是不安全的。
今天我们来看一下,JUC包下的AtomicInteger和AtomicIntegerArray
测试主类:
package juc.automic;

import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicIntegerArray;
/**
 * 测试AtomicInteger
 * @author donald
 * 2017年2月28日
 * 下午7:01:47
 */
public class TestAtomicInteger {
	public static void main(String[] args) {
		//测试 AtomicInteger
		AtomicInteger testInteger = new AtomicInteger(0);
		System.out.println("=======get:"+testInteger.get());
		System.out.println("=======addAndGet:"+testInteger.addAndGet(3));
		System.out.println("=======incrementAndGet:"+testInteger.incrementAndGet());
		System.out.println("=======decrementAndGet:"+testInteger.decrementAndGet());
		System.out.println("=======getAndAdd:"+testInteger.getAndAdd(2));
		System.out.println("=======getAndIncrement:"+testInteger.getAndIncrement());
		System.out.println("=======getAndDecrement:"+testInteger.getAndDecrement());
		System.out.println("=======getAndSet:"+testInteger.getAndSet(7));
		System.out.println("=======compareAndSet:"+testInteger.compareAndSet(7, 8));
		System.out.println("=======get:"+testInteger.get());
		System.out.println("=======compareAndSet:"+testInteger.weakCompareAndSet(8, 9));
		System.out.println("=======get:"+testInteger.get());
		testInteger.lazySet(6);
		System.out.println("=======get:"+testInteger.get());
		//测试 AtomicIntegerArray
		AtomicIntegerArray testArray = new AtomicIntegerArray(10);
		testArray.set(0, 1);
		System.out.println("Array=======get:"+testArray.get(0));
		System.out.println("Array=======getAndAdd:"+testArray.getAndAdd(0, 2));
		System.out.println("Array=======getAndIncrement:"+testArray.getAndIncrement(0));
		System.out.println("Array=======getAndDecrement:"+testArray.getAndDecrement(0));
		System.out.println("Array=======getAndSet:"+testArray.getAndSet(0, 5));
		System.out.println("Array=======incrementAndGet:"+testArray.incrementAndGet(0));
		System.out.println("Array=======decrementAndGet:"+testArray.decrementAndGet(0));
		System.out.println("Array=======addAndGet:"+testArray.addAndGet(0, 3));
				
	}
}

AtomicInteger和AtomicIntegerArray的方法一看方法名,就知道其作用,我们今天来看一下,方法的具体实现;
//AtomicInteger
public class AtomicInteger extends Number implements java.io.Serializable {
    private static final long serialVersionUID = 6214790243416807050L;

    // setup to use Unsafe.compareAndSwapInt for updates
    //JNI ,硬件级别的原子操作
    private static final Unsafe unsafe = Unsafe.getUnsafe();
    private static final long valueOffset;

    static {
      try {
        valueOffset = unsafe.objectFieldOffset
            (AtomicInteger.class.getDeclaredField("value"));
      } catch (Exception ex) { throw new Error(ex); }
    }
   //volatile 值的修改对所欲线程可见
    private volatile int value;

    /**
     * Creates a new AtomicInteger with the given initial value.
     *
     * @param initialValue the initial value
     */
    public AtomicInteger(int initialValue) {
        value = initialValue;
    }
}

相关方法:
 /**
     * Gets the current value.
     *
     * @return the current value
     */
    public final int get() {
        return value;
    }

/**
 * Sets to the given value.
 *
 * @param newValue the new value
 */
public final void set(int newValue) {
    value = newValue;
}


/**
     * Eventually sets to the given value.
     *
     * @param newValue the new value
     * @since 1.6
     */
    public final void lazySet(int newValue) {
        unsafe.putOrderedInt(this, valueOffset, newValue);
    }

lazySet含义:最后设置为给定值。延时设置变量值,这个等价于set()方法,但是由于字段是volatile类型的,因此次字段的修改会比普通字段(非volatile字段)有稍微的性能延时(尽管可以忽略),所以如果不是想立即读取设置的新值,允许在“后台”修改值,那么此方法就很有用。如果还是难以理解,这里就类似于启动一个后台线程如执行修改新值的任务,原线程就不等待修改结果立即返回(这种解释其实是不正确的,但是可以这么理解)。

 public final int getAndSet(int newValue) {
        for (;;) {
            int current = get();
            if (compareAndSet(current, newValue))
                return current;
        }
    }
       public final int getAndIncrement() {
        for (;;) {
            int current = get();
            int next = current + 1;
            if (compareAndSet(current, next))
                return current;
        }
    }

从上面两个方法,可以看出,getAndIncrement和getAndSet,保证原子性操作,通过compareAndSet(CAS原理)


  public final boolean compareAndSet(int expect, int update) {
        return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
    }

compareAndSet方法含义:
如果当前值== 预期值,则以原子方式将该值设置为给定的更新值。
如果成功就返回true,否则返回false,并且不修改原值。
 public final boolean weakCompareAndSet(int expect, int update) {
        return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
    }


weakCompareAndSet方法含义:
如果当前值== 预期值,则以原子方式将该设置为给定的更新值。JSR规范中说:以原子方式读取和有条件地写入变量但不创建任何happen-before 排序,因此不提供与除weakCompareAndSet 目标外任何变量以前或后续读取或写入操作有关的任何保证。大意就是说调用weakCompareAndSet时并不能保证不存在happen-before的发生(也就是可能存在指令重排序导致此操作失败)。但是从Java源码来看,其实此方法并没有实现JSR规范的要求,最后效果和compareAndSet是等效的,都调用了unsafe.compareAndSwapInt()完成操作。

//unsafe
public final class Unsafe
{

    private static native void registerNatives();

    private Unsafe()
    {
    }

    public static Unsafe getUnsafe()
    {
        Class class1 = Reflection.getCallerClass(2);
        if(class1.getClassLoader() != null)
            throw new SecurityException("Unsafe");
        else
            return theUnsafe;
    }

    public native int getInt(Object obj, long l);

    public native void putInt(Object obj, long l, int i);
    ....
     public final native boolean compareAndSwapObject(Object obj, long l, Object obj1, Object obj2);

    public final native boolean compareAndSwapInt(Object obj, long l, int i, int j);

    public final native boolean compareAndSwapLong(Object obj, long l, long l1, long l2);
}

再来看:
public class AtomicIntegerArray implements java.io.Serializable {
    private static final long serialVersionUID = 2862133569453604235L;

    private static final Unsafe unsafe = Unsafe.getUnsafe();
    private static final int base = unsafe.arrayBaseOffset(int[].class);
    private static final int shift;
    //存放数组元素
    private final int[] array;

    static {
        int scale = unsafe.arrayIndexScale(int[].class);
        if ((scale & (scale - 1)) != 0)
            throw new Error("data type scale not a power of two");
        shift = 31 - Integer.numberOfLeadingZeros(scale);
    }
}
//构造
 public AtomicIntegerArray(int length) {
        array = new int[length];
    }

//获取值
public final int get(int i) {
        return getRaw(checkedByteOffset(i));
    }

    private int getRaw(long offset) {
        return unsafe.getIntVolatile(array, offset);
    }
//设置
  public final void set(int i, int newValue) {
        unsafe.putIntVolatile(array, checkedByteOffset(i), newValue);
    }


  public final int getAndSet(int i, int newValue) {
        long offset = checkedByteOffset(i);
        while (true) {
            int current = getRaw(offset);
            if (compareAndSetRaw(offset, current, newValue))
                return current;
        }
    }
    private boolean compareAndSetRaw(long offset, int expect, int update) {
        return unsafe.compareAndSwapInt(array, offset, expect, update);
    }
     public final boolean compareAndSet(int i, int expect, int update) {
        return compareAndSetRaw(checkedByteOffset(i), expect, update);
    }


从上可以看,相关方法是通过JNI实现

//unsafe
public native int getIntVolatile(Object obj, long l);
public native void putIntVolatile(Object obj, long l, int i);
public native long allocateMemory(long l);
public native long reallocateMemory(long l, long l1);
public native void freeMemory(long l);


0
0
分享到:
评论

相关推荐

    Java AtomicInteger类的使用方法详解

    源码解析 AtomicInteger类的源码中,使用了volatile关键字来确保多线程可以共享变量。它还使用了Unsafe类的compareAndSwapInt方法来实现原子操作。源码中还使用了static块来初始化valueOffset变量。 实例使用 在...

    java多线程自增效率比较及原理解析

    ### Java多线程自增效率比较及原理解析 #### 一、引言 在Java多线程环境中,自增操作是一种非常常见的需求。然而,由于多线程环境中的并发执行特性,简单的自增操作可能会导致数据不一致等问题。因此,在进行自增...

    ThreadPoolExecutor源码解析.pdf

    《ThreadPoolExecutor源码解析》 ThreadPoolExecutor是Java并发编程中重要的组件,它是ExecutorService接口的实现,用于管理和调度线程的执行。理解其源码有助于我们更好地控制并发环境下的任务执行,提高系统的...

    算法、常用数据结构、文件资料、多线程和XML解析 资料汇总

    - **同步机制**:Java 提供了多种同步机制,如 `synchronized` 关键字、显式锁(`Lock` 接口)、原子变量类 (`AtomicInteger`, `AtomicLong`) 等。 ### 知识点五:XML 解析 - **XML 概念**:XML(Extensible ...

    线程池源码解析-多线程

    本文将深入解析线程池的源码,特别关注其中的`AtomicInteger`类以及线程池状态的表示。 `AtomicInteger`是Java并发包`java.util.concurrent.atomic`中的一个原子类型类,它提供了在多线程环境下安全地修改整型变量...

    探索Java并发的基石:同步机制的全面解析

    ### Java 并发基石:同步机制的全面解析 #### Java 的并发编程背景 Java作为一种广泛应用的编程语言,自1995年由Sun Microsystems(现属于Oracle公司)发布以来,已经发展成为一种支持跨平台性、面向对象编程、多...

    【电子版】校招面试题库(附答案与解析)java篇.zip

    这份压缩包包含了一份详细的PDF文档,全面覆盖了Java编程语言在校园招聘面试中的常见问题、答案以及深入解析,旨在帮助应聘者在面试中展现出扎实的技术功底。 一、Java基础篇 1. Java发展历程:从Sun Microsystems...

    Java中高级核心知识全面解析

    理解线程同步机制,如synchronized、volatile、Lock接口以及原子类(AtomicInteger、AtomicReference等)的应用至关重要。此外,学习如何避免死锁、活锁和饥饿现象也是多线程编程的关键。 2. **集合框架**:深入...

    《Java并发编程高阶技术-高性能并发框架源码解析与实战》学习.zip

    此外,书中可能还会涉及Java内存模型(JMM)、 volatile关键字、synchronized的使用方式、原子类(AtomicInteger、AtomicReference等)以及Lock接口(ReentrantLock、ReadWriteLock等)等主题,这些都是理解和编写...

    Java原子操作CAS原理解析

    Java原子操作CAS原理解析 Java原子操作CAS原理解析是Java并发编程中的一种机制,用于解决多线程并行情况下使用锁造成的性能损耗。CAS操作包含三个操作数——内存位置(V)、预期原值(A)、新值(B)。如果内存位置的...

    基于Java的动态站点中计数器的实现与解析.zip

    为了确保计数的准确性和并发安全性,Java提供synchronized关键字和java.util.concurrent包下的工具类,如AtomicInteger,来保证多线程环境下的计数操作不会出现数据不一致的问题。 再者,动态生成页面是动态网站的...

    Java大厂面试题汇总及答案解析.docx

    【Java大厂面试题汇总及答案解析】 1. 继承相关知识点: - Java的继承特性:Java语言中,一个子类只能继承一个父类,这是Java的单继承特性,选项A描述错误。继承的目的在于提高代码的复用性和扩展性,父类通常包含...

    校招Java开发岗面试知识点解析.docx

    "Java开发岗面试知识点解析" Java是一种广泛应用的编程语言,作为Java开发岗的面试者,需要掌握的知识点很多。以下是面试中可能遇到的知识点总结: 1. Java基础知识点 Java是一种面向对象的编程语言,具有封装、...

    Java原子变量类原理及实例解析

    Java原子变量类原理及实例解析 一、原子变量类简介 Java中的原子变量类是为了解决多线程环境下数据的一致性问题而设计的。它可以确保多线程环境下数据的原子性、可见性和有序性。原子变量类的主要特点是它可以在多...

    java 分页、批量删除

    2. **后端处理**:服务器接收到请求后,解析选中的ID集合,然后构建删除语句。这里需要注意防止SQL注入。 3. **数据库操作**:执行删除SQL,删除指定的记录。批量删除可能会涉及到事务管理,确保数据的一致性。 4....

    用Java代码所写的简单计数器

    以上就是关于"用Java代码所写的简单计数器"的详细解析,希望这个解释能帮助你理解和构建类似的Java应用。在实践中,你可能需要根据具体需求进行调整,例如添加错误处理,或者使用更复杂的数据结构和图形库来提高用户...

    Java多线程CAS操作原理代码实例解析

    Java多线程CAS操作原理代码实例解析 在Java多线程编程中,CAS操作(Compare-And-Swap)是一种常用的无锁优化技术,它可以代替传统的加锁机制来实现线程安全。CAS操作的原理是比较并交换变量的值,如果变量的值与...

    Java常见2023年最新面试题,附答案解析

    本篇将基于2023年的最新趋势,解析Java面试中的常见问题及答案。 1. **Java基础** - **面向对象**:理解类、对象、封装、继承、多态的概念。 - **异常处理**:熟悉try-catch-finally语句块,了解Checked与...

    java concurrent 包 详细解析

    Java并发包中的某些类如`AtomicInteger`、`ConcurrentHashMap`等是线程安全的,无需额外的同步措施。 2. **Executor框架**:`java.util.concurrent.Executor`是执行任务的核心接口,它定义了运行任务的方法。`...

    基于Java的多线程网络爬虫设计与实现.pdf

    - 通过`AtomicInteger`保证计数操作的原子性,避免线程间的竞争条件。 - 利用`synchronized`关键字确保数据访问的同步性,防止并发访问引起的数据不一致问题。 ##### 2.4 正则表达式与HTML解析 - **问题描述**:...

Global site tag (gtag.js) - Google Analytics