本文共 4128 字,大约阅读时间需要 13 分钟。
因为java的多线程的缘故,当多个线程同时修改同一个变量,导致最后变量得不到预期的结果。原因是多线程操作,导致变量操作缺少原子性,所以导致变量在多线程的操作下达不到预期效果。
如下面案例所示:
public class Test { private static int count = 10; private static AtomicInteger atomicCount = new AtomicInteger(10); private static final ExecutorService executorService = Executors.newFixedThreadPool(4); public static void main(String[] args) { for (int i = 0; i < 10; i++) { executorService.execute(new Runnable() { @Override public void run() { atomicExecute();// unAtomicExecute(); } }); } } private static void unAtomicExecute() { try { Thread.sleep(50); } catch (InterruptedException e) { e.printStackTrace(); } System.out.print(--count+" "); } private static void atomicExecute() { try { Thread.sleep(50);//使得效果更明显 } catch (InterruptedException e) { e.printStackTrace(); } System.out.print( atomicCount.decrementAndGet()+" "); }}unAtomicExecute()方法执行的结果为:9 9 8 9 7 5 4 6 3 2 atomicExecute()方法执行的结果为:9 6 8 7 5 2 4 3 1 0 从打印的结果看出,unAtomicExecute()出现重复的数字,证明其对数字的操作是不具有原子性的。atomicExecute()使用的是AtomicInteger是具有原子性的。
在Java
从JDK1.5
提供了java.util.concurrent.atomic
包(简称Atomic
包),这个包中的原子操作类提供了一种用法简单、性能高效、线程安全地更新一个变量的方式。
在Atomic
包提供4种类型的原子类。
原子更新基本类型
AtomicBoolean:原子更新布尔类型AtomicInteger:原子更新整型AtomicLong:原子更新长整型
AtomicBoolean
、AtomicInteger
和AtomicLong
的实现相差无几,这里通过AtomicInteger
常用API来介绍。
AtomicInteger的构造
public AtomicInteger(int var1) { //传入 初始值 this.value = var1;}public AtomicInteger() { //默认初始值}
常用方法
public final int get() { //获取当前值 return this.value;}public final void set(int var1) { //设置值 this.value = var1;}public final int getAndIncrement() { //先获取当前值后在自增1 return unsafe.getAndAddInt(this, valueOffset, 1);}public final int getAndDecrement() { ////先获取当前值后在加自减1 return unsafe.getAndAddInt(this, valueOffset, -1);}public final int getAndAdd(int var1) { //先获取当前值后再加上传入参数的值 return unsafe.getAndAddInt(this, valueOffset, var1);}public final int incrementAndGet() { //先自增1,再获取当前值 return unsafe.getAndAddInt(this, valueOffset, 1) + 1;}public final int decrementAndGet() { //先自减1,再获取当前值 return unsafe.getAndAddInt(this, valueOffset, -1) - 1;}public final int addAndGet(int var1) { //先加上传入参数的值,再获取当前值 return unsafe.getAndAddInt(this, valueOffset, var1) + var1;}
原子更新数组
AtomicIntegerArray:原子更新整型数组里的元素AtomicLongArray:原子更新长整型数组里的元素。AtomicReferenceArray:原子更新引用类型数组里的元素
在java中,提供了许多好用的防并发的容器,所以上面提到的一般都不常用。
原子更新引用
AtomicReference:原子更新引用类型AtomicReferenceFieldUpdater:原子更新引用类型里的字段AtomicMarkableReference:原子更新带有标记位的引用类型
这3个类的实现方法基本一样,这里就以AtomicReference写一个示例。
public class AtomicReferenceTest { public static AtomicReferenceatomicUserRef = new AtomicReference (); public static void main(String[] args) { User user = new User("lisi", 16); atomicUserRef.set(user); System.out.println(atomicUserRef.get().getName() + " " + atomicUserRef.get().getOld()); System.out.println("-------------------------"); User updateUser = new User("zhangsan", 18); atomicUserRef.compareAndSet(user, updateUser); System.out.println(atomicUserRef.get().getName() + " " + atomicUserRef.get().getOld()); } static class User { private String name; private int old; public User(String name, int old) { this.name = name; this.old = old; } public String getName() { return name; } public int getOld() { return old; } } }打印结果:lisi 16-------------------------zhangsan 18
原子更新属性
AtomicIntegerFieldUpdater:原子更新整型的字段的更新器AtomicLongFieldUpdater:原子更新长整型字段的更新器AtomicStampedReference:原子更新带有版本号的引用类型
这几个类用的用的比较少,使用方法和上面的类似,类也不复杂,有兴趣可以了解下源码,这里就不写例子了。
转载地址:http://qesvn.baihongyu.com/