JAVA多线程之JUC原子类

JUC原子类框架

JUC即是指:java.util.concurrent包。

  1. 基本类型: AtomicInteger, AtomicLong, AtomicBoolean ;
  2. 数组类型: AtomicIntegerArray, AtomicLongArray, AtomicReferenceArray ;
  3. 引用类型: AtomicReference, AtomicStampedRerence, AtomicMarkab-

    leReference ;

  4. 对象的属性修改类型: AtomicIntegerFieldUpdater, AtomicLongFieldUp-

    dater, AtomicReferenceFieldUpdater 。

CAS操作

基本概念

CAS是单词compare and set的缩写,意思是指在set之前先比较该值有没有变化,只有在没变的情况下才对其赋值。

CAS码追踪分析

今天有时间跟踪了一下AtomicInteger的incrementAndGet的实现.

1. incrementAndGet的实现

整型自增加1操作CAS的实现

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

首先可以看到他是通过一个无限循环(spin)直到increment成功为止.

循环的内容是

1.取得当前值

2.计算+1后的值

3.如果当前值还有效(没有被)的话设置那个+1后的值

4.如果设置没成功(当前值已经无效了即被别的线程改过了), 再从1开始.

2. compareAndSet的实现

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

compareAndSet()的作用是更新AtomicInteger对应的int值。它会比较AtomicInteger的原始值是否与expect相等,若相等的话,则设置AtomicInteger的值为update。

3. compareAndSwapInt的实现

   /**
     * Atomically update Java variable to <tt>x</tt> if it is currently
     * holding <tt>expected</tt>.
     * @return <tt>true</tt> if successful
     */
    public final native boolean compareAndSwapInt(Object o, long offset,int expected,int x);

可以看到, 不是用Java实现的, 而是通过JNI调用操作系统的原生程序.

4. compareAndSwapInt的native实现

如果你下载了OpenJDK的源代码的话在hotspot\src\share\vm\prims\目录下可以找到unsafe.cpp

UNSAFE_ENTRY(jboolean, Unsafe_CompareAndSwapInt(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jint e, jint x))
  UnsafeWrapper("Unsafe_CompareAndSwapInt");
  oop p = JNIHandles::resolve(obj);
  jint* addr = (jint *) index_oop_from_field_offset_long(p, offset);
  return (jint)(Atomic::cmpxchg(x, addr, e)) == e;
UNSAFE_END

可以看到实际上调用Atomic类的cmpxchg方法.

5. Atomic的cmpxchg

这个类的实现是跟操作系统有关, 跟CPU架构也有关, 如果是windows下x86的架构

核心方法是compxchg,这个方法所属的类文件是在OS_CPU目录下面,由此可以看出这个类是和CPU操作有关,进入代码如下:

inline jint     Atomic::cmpxchg    (jint     exchange_value, volatile jint*     dest, jint     compare_value) {
  // alternative for InterlockedCompareExchange
  int mp = os::is_MP();
  __asm {
    mov edx, dest
    mov ecx, exchange_value
    mov eax, compare_value
    LOCK_IF_MP(mp)
    cmpxchg dword ptr [edx], ecx
  }
}

在这里可以看到是用嵌入的汇编实现的, 关键CPU指令是 cmpxchg

到这里没法再往下找代码了. 也就是说CAS的原子性实际上是CPU实现的.

这个方法里面都是汇编指命,看到LOCK_IF_MP也有锁指令实现的原子操作,其实CAS也算是有锁操作,只不过是由CPU来触发,比synchronized性能好的多。

总结

此外,java.util.concurrent.ConcurrentLinkedQueue类全是采用的非阻塞算法,里面没有使用任何锁,全是基于CAS操作实现的。CAS操作可以说是JAVA并发框架的基础,整个框架的设计都是基于CAS操作的。

缺点:

1、ABA问题

CAS操作容易导致ABA问题,也就是在做a++之间,a可能被多个线程修改过了,只不过回到了最初的值,这时CAS会认为a的值没有变。a在外面逛了一圈回来,你能保证它没有做任何坏事,不能!!也许它讨闲,把b的值减了一下,把c的值加了一下等等,更有甚者如果a是一个对象,这个对象有可能是新创建出来的,a是一个引用呢情况又如何,所以这里面还是存在着很多问题的,解决ABA问题的方法有很多,可以考虑增加一个修改计数,只有修改计数不变的且a值不变的情况下才做a++,也可以考虑引入版本号,当版本号相同时才做a++操作等,这和事务原子性处理有点类似!

2、比较花费CPU资源,即使没有任何争用也会做一些无用功。

3、会增加程序测试的复杂度,稍不注意就会出现问题。

总结:

可以用CAS在无锁的情况下实现原子操作,但要明确应用场合,非常简单的操作且又不想引入锁可以考虑使用CAS操作,当想要非阻塞地完成某一操作也可以考虑CAS。不推荐在复杂操作中引入CAS,会使程序可读性变差,且难以测试,同时会出现ABA问题。

AtomicLong

AtomicInteger, AtomicLong和AtomicBoolean这3个基本类型的原子类的原理和用法相似。本章以AtomicLong对基本类型的原子类进行介绍。

AtomicLong是作用是对长整形进行原子操作。

在32位操作系统中,64位的long 和 double 变量由于会被JVM当作两个分离的32位来进行操作,所以不具有原子性。而使用AtomicLong能让long的操作保持原子型。

代码示例:

// LongTest.java的源码
import java.util.concurrent.atomic.AtomicLong;

public class LongTest {

    public static void main(String[] args){

        // 新建AtomicLong对象
        AtomicLong mAtoLong = new AtomicLong();

        mAtoLong.set(0x0123456789ABCDEFL);
        System.out.printf("%20s : 0x%016X\n", "get()", mAtoLong.get());
        System.out.printf("%20s : 0x%016X\n", "intValue()", mAtoLong.intValue());
        System.out.printf("%20s : 0x%016X\n", "longValue()", mAtoLong.longValue());
        System.out.printf("%20s : %s\n", "doubleValue()", mAtoLong.doubleValue());
        System.out.printf("%20s : %s\n", "floatValue()", mAtoLong.floatValue());

        System.out.printf("%20s : 0x%016X\n", "getAndDecrement()", mAtoLong.getAndDecrement());
        System.out.printf("%20s : 0x%016X\n", "decrementAndGet()", mAtoLong.decrementAndGet());
        System.out.printf("%20s : 0x%016X\n", "getAndIncrement()", mAtoLong.getAndIncrement());
        System.out.printf("%20s : 0x%016X\n", "incrementAndGet()", mAtoLong.incrementAndGet());

        System.out.printf("%20s : 0x%016X\n", "addAndGet(0x10)", mAtoLong.addAndGet(0x10));
        System.out.printf("%20s : 0x%016X\n", "getAndAdd(0x10)", mAtoLong.getAndAdd(0x10));

        System.out.printf("\n%20s : 0x%016X\n", "get()", mAtoLong.get());

        System.out.printf("%20s : %s\n", "compareAndSet()", mAtoLong.compareAndSet(0x12345679L, 0xFEDCBA9876543210L));
        System.out.printf("%20s : 0x%016X\n", "get()", mAtoLong.get());

        System.out.printf("%20s : %s\n", "compareAndSet()", mAtoLong.compareAndSet(0x0123456789ABCE0FL, 0xFEDCBA9876543210L));
        System.out.printf("%20s : 0x%016X\n", "get()", mAtoLong.get());
    }
}
/*
get() : 0x0123456789ABCDEF
          intValue() : 0x0000000089ABCDEF
         longValue() : 0x0123456789ABCDEF
       doubleValue() : 8.1985529216486896E16
        floatValue() : 8.1985531E16
   getAndDecrement() : 0x0123456789ABCDEF
   decrementAndGet() : 0x0123456789ABCDED
   getAndIncrement() : 0x0123456789ABCDED
   incrementAndGet() : 0x0123456789ABCDEF
     addAndGet(0x10) : 0x0123456789ABCDFF
     getAndAdd(0x10) : 0x0123456789ABCDFF

               get() : 0x0123456789ABCE0F
     compareAndSet() : false
               get() : 0x0123456789ABCE0F
     compareAndSet() : true
               get() : 0xFEDCBA9876543210
               */

AtomicLongArray

在”Java多线程系列–“JUC原子类”02之 AtomicLong原子类”中介绍过,AtomicLong是作用是对长整形进行原子操作。而AtomicLongArray的作用则是对”长整形数组”进行原子操作。

AtomicLongArray函数列表

// 创建给定长度的新 AtomicLongArray。
AtomicLongArray(int length)
// 创建与给定数组具有相同长度的新 AtomicLongArray,并从给定数组复制其所有元素。
AtomicLongArray(long[] array)

// 以原子方式将给定值添加到索引 i 的元素。
long addAndGet(int i, long delta)
// 如果当前值 == 预期值,则以原子方式将该值设置为给定的更新值。
boolean compareAndSet(int i, long expect, long update)
// 以原子方式将索引 i 的元素减1。
long decrementAndGet(int i)
// 获取位置 i 的当前值。
long get(int i)
// 以原子方式将给定值与索引 i 的元素相加。
long getAndAdd(int i, long delta)
// 以原子方式将索引 i 的元素减 1。
long getAndDecrement(int i)
// 以原子方式将索引 i 的元素加 1。
long getAndIncrement(int i)
// 以原子方式将位置 i 的元素设置为给定值,并返回旧值。
long getAndSet(int i, long newValue)
// 以原子方式将索引 i 的元素加1。
long incrementAndGet(int i)
// 最终将位置 i 的元素设置为给定值。
void lazySet(int i, long newValue)
// 返回该数组的长度。
int length()
// 将位置 i 的元素设置为给定值。
void set(int i, long newValue)
// 返回数组当前值的字符串表示形式。
String toString()
// 如果当前值 == 预期值,则以原子方式将该值设置为给定的更新值。
boolean    weakCompareAndSet(int i, long expect, long update)

AtomicLongArray的代码很简单,下面仅以incrementAndGet()为例,对AtomicLong的原理进行说明。

incrementAndGet()源码如下:

public final long incrementAndGet(int i) {
    return addAndGet(i, 1);
}

说明:incrementAndGet()的作用是以原子方式将long数组的索引 i 的元素加1,并返回加1之后的值。

addAndGet()源码如下:

public long addAndGet(int i, long delta) {
    // 检查数组是否越界
    long offset = checkedByteOffset(i);
    while (true) {
        // 获取long型数组的索引 offset 的原始值
        long current = getRaw(offset);
        // 修改long型值
        long next = current + delta;
        // 通过CAS更新long型数组的索引 offset的值。
        if (compareAndSetRaw(offset, current, next))
            return next;
    }
}

说明:addAndGet()首先检查数组是否越界。如果没有越界的话,则先获取数组索引i的值;然后通过CAS函数更新i的值。

getRaw()源码如下:

private long getRaw(long offset) {
    return unsafe.getLongVolatile(array, offset);
}

说明:unsafe是通过Unsafe.getUnsafe()返回的一个Unsafe对象。通过Unsafe的CAS函数对long型数组的元素进行原子操作。如compareAndSetRaw()就是调用Unsafe的CAS函数,它的源码如下:

private boolean compareAndSetRaw(long offset, long expect, long update) {
    return unsafe.compareAndSwapLong(array, offset, expect, update);
}

代码示例

// LongArrayTest.java的源码
import java.util.concurrent.atomic.AtomicLongArray;

public class LongArrayTest {

    public static void main(String[] args){

        // 新建AtomicLongArray对象
        long[] arrLong = new long[] {10, 20, 30, 40, 50};
        AtomicLongArray ala = new AtomicLongArray(arrLong);

        ala.set(0, 100);
        for (int i=0, len=ala.length(); i<len; i++)
            System.out.printf("get(%d) : %s\n", i, ala.get(i));

        System.out.printf("%20s : %s\n", "getAndDecrement(0)", ala.getAndDecrement(0));
        System.out.printf("%20s : %s\n", "decrementAndGet(1)", ala.decrementAndGet(1));
        System.out.printf("%20s : %s\n", "getAndIncrement(2)", ala.getAndIncrement(2));
        System.out.printf("%20s : %s\n", "incrementAndGet(3)", ala.incrementAndGet(3));

        System.out.printf("%20s : %s\n", "addAndGet(100)", ala.addAndGet(0, 100));
        System.out.printf("%20s : %s\n", "getAndAdd(100)", ala.getAndAdd(1, 100));

        System.out.printf("%20s : %s\n", "compareAndSet()", ala.compareAndSet(2, 31, 1000));
        System.out.printf("%20s : %s\n", "get(2)", ala.get(2));
    }
}
/*
get(0) : 100
get(1) : 20
get(2) : 30
get(3) : 40
get(4) : 50
  getAndDecrement(0) : 100
  decrementAndGet(1) : 19
  getAndIncrement(2) : 30
  incrementAndGet(3) : 41
      addAndGet(100) : 199
      getAndAdd(100) : 19
     compareAndSet() : true
              get(2) : 1000
*/

AtomicReference

AtomicReference是作用是对”对象”进行原子操作。

AtomicReference函数列表

// 使用 null 初始值创建新的 AtomicReference。
AtomicReference()
// 使用给定的初始值创建新的 AtomicReference。
AtomicReference(V initialValue)

// 如果当前值 == 预期值,则以原子方式将该值设置为给定的更新值。
boolean compareAndSet(V expect, V update)
// 获取当前值。
V get()
// 以原子方式设置为给定值,并返回旧值。
V getAndSet(V newValue)
// 最终设置为给定值。
void lazySet(V newValue)
// 设置为给定值。
void set(V newValue)
// 返回当前值的字符串表示形式。
String toString()
// 如果当前值 == 预期值,则以原子方式将该值设置为给定的更新值。
boolean weakCompareAndSet(V expect, V update)

在JDK1.7.0_40中AtomicReference.java的源码如下:

public class AtomicReference<V>  implements java.io.Serializable {
    private static final long serialVersionUID = -1848883965231344442L;

    // 获取Unsafe对象,Unsafe的作用是提供CAS操作
    private static final Unsafe unsafe = Unsafe.getUnsafe();
    private static final long valueOffset;

    static {
      try {
        valueOffset = unsafe.objectFieldOffset
            (AtomicReference.class.getDeclaredField("value"));
      } catch (Exception ex) { throw new Error(ex); }
    }

    // volatile类型
    private volatile V value;

    public AtomicReference(V initialValue) {
        value = initialValue;
    }

    public AtomicReference() {
    }

    public final V get() {
        return value;
    }

    public final void set(V newValue) {
        value = newValue;
    }

    public final void lazySet(V newValue) {
        unsafe.putOrderedObject(this, valueOffset, newValue);
    }

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

    public final boolean weakCompareAndSet(V expect, V update) {
        return unsafe.compareAndSwapObject(this, valueOffset, expect, update);
    }

    public final V getAndSet(V newValue) {
        while (true) {
            V x = get();
            if (compareAndSet(x, newValue))
                return x;
        }
    }

    public String toString() {
        return String.valueOf(get());
    }
}

说明:

AtomicReference的源码比较简单。它是通过”volatile”和”Unsafe提供的CAS函数实现”原子操作。

(01) value是volatile类型。这保证了:当某线程修改value的值时,其他线程看到的value值都是最新的value值,即修改之后的volatile的值。

(02) 通过CAS设置value。这保证了:当某线程池通过CAS函数(如compareAndSet函数)设置value时,它的操作是原子的,即线程在操作value时不会被中断。

代码示例

// AtomicReferenceTest.java的源码
import java.util.concurrent.atomic.AtomicReference;

public class AtomicReferenceTest {

    public static void main(String[] args){

        // 创建两个Person对象,它们的id分别是101和102。
        Person p1 = new Person(101);
        Person p2 = new Person(101);
        // 新建AtomicReference对象,初始化它的值为p1对象
        AtomicReference ar = new AtomicReference(p1);
        // 通过CAS设置ar。如果ar的值为p1的话,则将其设置为p2。
        ar.compareAndSet(p1, p2);

        Person p3 = (Person)ar.get();
        System.out.println("p3 is "+p3);
        System.out.println("p3.equals(p1)="+p3.equals(p1));
        System.out.println("p3.equals(p2)="+p3.equals(p2));
    }
}

class Person {
    volatile long id;
    public Person(long id) {
        this.id = id;
    }
    public String toString() {
        return "id:"+id;
    }
}
/*运行结果:
p3 is id:102
p3.equals(p1)=false
p3.equals(p2)=true
*/

结果说明:

新建AtomicReference对象ar时,将它初始化为p1。

紧接着,通过CAS函数对它进行设置。如果ar的值为p1的话,则将其设置为p2。

最后,获取ar对应的对象,并打印结果。p3.equals(p1)的结果为false,这是因为Person并没有覆盖equals()方法,而是采用继承自Object.java的equals()方法;而Object.java中的equals()实际上是调用”==”去比较两个对象,即比较两个对象的地址是否相等。

AtomicLongFieldUpdate

AtomicLongFieldUpdater可以对指定”类的 ‘volatile long’类型的成员”进行原子更新。它是基于反射原理实现的。

AtomicLongFieldUpdater函数列表

// 受保护的无操作构造方法,供子类使用。
protected AtomicLongFieldUpdater()

// 以原子方式将给定值添加到此更新器管理的给定对象的字段的当前值。
long addAndGet(T obj, long delta)
// 如果当前值 == 预期值,则以原子方式将此更新器所管理的给定对象的字段设置为给定的更新值。
abstract boolean compareAndSet(T obj, long expect, long update)
// 以原子方式将此更新器管理的给定对象字段当前值减 1。
long decrementAndGet(T obj)
// 获取此更新器管理的在给定对象的字段中保持的当前值。
abstract long get(T obj)
// 以原子方式将给定值添加到此更新器管理的给定对象的字段的当前值。
long getAndAdd(T obj, long delta)
// 以原子方式将此更新器管理的给定对象字段当前值减 1。
long getAndDecrement(T obj)
// 以原子方式将此更新器管理的给定对象字段的当前值加 1。
long getAndIncrement(T obj)
// 将此更新器管理的给定对象的字段以原子方式设置为给定值,并返回旧值。
long getAndSet(T obj, long newValue)
// 以原子方式将此更新器管理的给定对象字段当前值加 1。
long incrementAndGet(T obj)
// 最后将此更新器管理的给定对象的字段设置为给定更新值。
abstract void lazySet(T obj, long newValue)
// 为对象创建并返回一个具有给定字段的更新器。
static <U> AtomicLongFieldUpdater<U> newUpdater(Class<U> tclass, String fieldName)
// 将此更新器管理的给定对象的字段设置为给定更新值。
abstract void set(T obj, long newValue)
// 如果当前值 == 预期值,则以原子方式将此更新器所管理的给定对象的字段设置为给定的更新值。
abstract boolean weakCompareAndSet(T obj, long expect, long update)

AtomicLongFieldUpdater示例

// LongTest.java的源码
import java.util.concurrent.atomic.AtomicLongFieldUpdater;

public class LongFieldTest {

    public static void main(String[] args) {

        // 获取Person的class对象
        Class cls = Person.class;
        // 新建AtomicLongFieldUpdater对象,传递参数是“class对象”和“long类型在类中对应的名称”
        AtomicLongFieldUpdater mAtoLong = AtomicLongFieldUpdater.newUpdater(cls, "id");
        Person person = new Person(12345678L);

        // 比较person的"id"属性,如果id的值为12345678L,则设置为1000。
        mAtoLong.compareAndSet(person, 12345678L, 1000);
        System.out.println("id="+person.getId());
    }
}

class Person {
    volatile long id;
    public Person(long id) {
        this.id = id;
    }
    public void setId(long id) {
        this.id = id;
    }
    public long getId() {
        return id;
    }
}
/*运行结果
id=1000
*/

下面分析LongFieldTest.java的流程。

1. newUpdater()

newUpdater()的源码如下:

public static <U> AtomicLongFieldUpdater<U> newUpdater(Class<U> tclass, String fieldName) {
    Class<?> caller = Reflection.getCallerClass();
    if (AtomicLong.VM_SUPPORTS_LONG_CAS)
        return new CASUpdater<U>(tclass, fieldName, caller);
    else
        return new LockedUpdater<U>(tclass, fieldName, caller);
}

**说明:**newUpdater()的作用是获取一个AtomicIntegerFieldUpdater类型的对象。

它实际上返回的是CASUpdater对象,或者LockedUpdater对象;具体返回哪一个类取决于JVM是否支持long类型的CAS函数。CASUpdater和LockedUpdater都是AtomicIntegerFieldUpdater的子类,它们的实现类似。下面以CASUpdater来进行说明。

2. CASUpdater类的源码如下:

public boolean compareAndSet(T obj, long expect, long update) {
    if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj);
    return unsafe.compareAndSwapLong(obj, offset, expect, update);
}

说明:它实际上是通过CAS函数操作。如果类的long对象的值是expect,则设置它的值为update。

参考及原文

完美的总结:

http://www.cnblogs.com/skywang12345/p/java_threads_category.html

该大侠将java多线程总结的很好,本人只是参考学习整理,并对某些内容加入了自己的理解,并删除了繁杂部分

时间: 2024-10-02 06:27:51

JAVA多线程之JUC原子类的相关文章

Java多线程之JUC包:ReentrantReadWriteLock源码学习笔记

若有不正之处请多多谅解,并欢迎批评指正. 请尊重作者劳动成果,转载请标明原文链接: http://www.cnblogs.com/go2sea/p/5634701.html ReentrantLock提供了标准的互斥操作,但在应用中,我们对一个资源的访问有两种方式:读和写,读操作一般不会影响数据的一致性问题.但如果我们使用ReentrantLock,则在需要在读操作的时候也独占锁,这会导致并发效率大大降低.JUC包提供了读写锁ReentrantReadWriteLock,使得读写锁分离,在上述情

Java多线程之JUC包:Semaphore源码学习笔记

若有不正之处请多多谅解,并欢迎批评指正. 请尊重作者劳动成果,转载请标明原文链接: http://www.cnblogs.com/go2sea/p/5625536.html Semaphore是JUC包提供的一个共享锁,一般称之为信号量. Semaphore通过自定义的同步器维护了一个或多个共享资源,线程通过调用acquire获取共享资源,通过调用release释放. 源代码: /* * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to lic

Java多线程之JUC包:ReentrantLock源码学习笔记

若有不正之处请多多谅解,并欢迎批评指正. 请尊重作者劳动成果,转载请标明原文链接: http://www.cnblogs.com/go2sea/p/5627539.html ReentrantLock是JUC包提供的一种可重入独占锁,它实现了Lock接口.与Semaphore类似,ReentrantLock也提供了两种工作模式:公平模式&非公平模式,也是通过自定义两种同步器FairSync&NonfairSync来实现的. 源代码: /* * ORACLE PROPRIETARY/CONF

java多线程系类:JUC原子类:03之AtomicLongArray原子类

概要 AtomicIntegerArray, AtomicLongArray, AtomicReferenceArray这3个数组类型的原子类的原理和用法相似.本章以AtomicLongArray对数组类型的原子类进行介绍.内容包括:AtomicLongArray介绍和函数列表AtomicLongArray源码分析(基于JDK1.7.0_40)AtomicLongArray示例 转载请注明出处:http://www.cnblogs.com/skywang12345/p/3514604.html

JAVA多线程之volatile 与 synchronized 的比较

一,volatile关键字的可见性 要想理解volatile关键字,得先了解下JAVA的内存模型,Java内存模型的抽象示意图如下: 从图中可以看出: ①每个线程都有一个自己的本地内存空间--线程栈空间???线程执行时,先把变量从主内存读取到线程自己的本地内存空间,然后再对该变量进行操作 ②对该变量操作完后,在某个时间再把变量刷新回主内存 关于JAVA内存模型,更详细的可参考: 深入理解Java内存模型(一)——基础 因此,就存在内存可见性问题,看一个示例程序:(摘自书上) 1 public c

JAVA多线程之wait/notify

本文主要学习JAVA多线程中的 wait()方法 与 notify()/notifyAll()方法的用法. ①wait() 与 notify/notifyAll 方法必须在同步代码块中使用 ②wait() 与  notify/notifyAll() 的执行过程 ③中断 调用wait()方法进入等待队列的 线程 ④notify 通知的顺序不能错 ⑤多线程中测试某个条件的变化用 if 还是用 while? ①wait() 与 notify/notifyAll 方法必须在同步代码块中使用 wait()

Java多线程之wait(),notify(),notifyAll()

在多线程的情况下,因为同一进程的多个线程共享同一片存储空间,在带来方便的同一时候,也带来了訪问冲突这个严重的问题.Java语言提供了专门机制以解决这样的冲突,有效避免了同一个数据对象被多个线程同一时候訪问. wait与notify是java同步机制中重要的组成部分.结合与synchronizedkeyword使用,能够建立非常多优秀的同步模型. synchronized(this){ }等价于publicsynchronized void method(){.....} 同步分为类级别和对象级别

java多线程之ThreadLocal

ThreadLocal保证数据同步 package Thread.Common; import java.util.Random; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; class Accessor implements Runnable { private final int id; pub

java多线程之Future和FutureTask

Executor框架使用Runnable 作为其基本的任务表示形式.Runnable是一种有局限性的抽象,然后可以写入日志,或者共享的数据结构,但是他不能返回一个值. 许多任务实际上都是存在延迟计算的:执行数据库查询,从网络上获取资源,或者某个复杂耗时的计算.对于这种任务,Callable是一个更好的抽象,他能返回一个值,并可能抛出一个异常.Future表示一个任务的周期,并提供了相应的方法来判断是否已经完成或者取消,以及获取任务的结果和取消任务. public interface Callab