本文共 5609 字,大约阅读时间需要 18 分钟。
JUC包中除了锁,还提供了原子操作类来实现线程对临界资源的互斥访问。
Atomic包中提供了多种类型的原子操作类:
它们都是CAS(compareAndSwap)来实现原子性。1.原子基本类型
用于原子更新基本类型,包括以下三类:AtomicInteger 常用方法:
public class AtomicIntegerTest { public static void main(String[] args) { AtomicInteger integer = new AtomicInteger(0); //递增 System.out.println("递增后的值: " + integer.incrementAndGet()); //递减 System.out.println("递减后的值: " + integer.decrementAndGet()); //增加20 System.out.println("增加20后的值: " + integer.updateAndGet((x)-> x + 20)); }}
运行结果:
递增后的值: 1递减后的值: 0增加20后的值: 20
2.原子引用类型
原子基本类型只能保证基本类型的原子性,如果要原子更新一个对象就需要使用原子引用类型。原子引用类型如下:
AtomicReference 主要方法:
下面以多个线程更新账户余额的例子来说明AtomicReference的使用
/*账户余额*/class AccountBalance { private BigDecimal banlance; public AccountBalance(BigDecimal banlance) { this.banlance = banlance; } public BigDecimal getBanlance() { return banlance; } public void setBanlance(BigDecimal banlance) { this.banlance = banlance; }}class UpdateBalanceRunnable implements Runnable { private AccountBalance accountBalance; private AtomicReferencereference; public UpdateBalanceRunnable(AtomicReference reference, AccountBalance accountBalance) { this.reference = reference; this.accountBalance = accountBalance; this.reference.set(this.accountBalance); } @Override public void run() { while(true) { AccountBalance prev = reference.get(); // 账户余额加10 AccountBalance next = new AccountBalance(prev.getBanlance(). add(new BigDecimal(10.0))); if (reference.compareAndSet(prev, next)){ //更新成功,退出,否则自旋 break; } } }}public class AtomicReferenceTest { public static void main(String[] args) throws InterruptedException { AccountBalance first = new AccountBalance(new BigDecimal(0)); System.out.println("更新前账户余额: " + first.getBanlance()); AtomicReference reference = new AtomicReference<>(first); UpdateBalanceRunnable runnable = new UpdateBalanceRunnable(reference,first); Thread t1 = new Thread(runnable); Thread t2 = new Thread(runnable); t1.start(); t2.start(); t1.join(); t2.join(); System.out.println("更新后账户余额: " + reference.get().getBanlance()); }}
运行结果:
更新前账户余额: 0更新后账户余额: 20
AtomicStampedReference主要方法:
public class AtomicStampedReferenceTest { public static void main(String[] args) { Integer integer1 = 0; Integer integer2 = 2; AtomicStampedReferencereference = new AtomicStampedReference (integer1,1); reference.compareAndSet(integer1,integer2,reference.getStamp(),reference.getStamp()+1); System.out.println("更新value后:" + reference.getReference()); boolean b = reference.attemptStamp(integer2, reference.getStamp() + 1); System.out.println("更新版本后: "+reference.getStamp()); boolean c = reference.compareAndSet(integer2,3,4, reference.getStamp()+1); if (!c) { System.out.println("CAS 操作失败"); } }}
运行结果:
更新value后:2更新版本后: 3CAS 操作失败
3.原子更新数组类型
Atomic包同样提供了对数组类型原子操作的类,主要包括:AtomicIntegerArray主要方法:
下面是一个多线程更新数组的例子。
public class AtomicIntegerArrayTest { public static void main(String[] args) throws InterruptedException { AtomicIntegerArray array = new AtomicIntegerArray(10); Listlist = new ArrayList (); System.out.println("数组未修改前:"); for (int i = 0; i < array.length(); ++i) { System.out.print(array.get(i) + "\t"); } for (int i = 0; i < 10; ++i) { Thread t = new Thread(() -> { //依次更新数组 for (int j = 0 ; j < array.length(); ++j) { array.incrementAndGet(j); } }); list.add(t); t.start(); } for (Thread t: list) { t.join(); } System.out.println("\n数组被修改后:"); for (int i = 0; i < array.length(); ++i) { System.out.print(array.get(i) + "\t"); } }}
运行结果:
数组未修改前:0 0 0 0 0 0 0 0 0 0 数组被修改后:100 100 100 100 100 100 100 100 100 100
转载地址:http://oecmb.baihongyu.com/