===============================================================================
-
int addAndGet(int delta
):以原子方式将输入的数值与实例中的值 (AtomicInteger 里的 value)相加,并返回结果。 -
boolean compareAndSet(int expect,int update)
:如果输入的数值等于预 期值,则以原子方式将该值设置为输入的值。 -
int getAndIncrement():
以原子方式将当前值加 1,注意,这里返回的是自增前的值。 -
int getAndSet(int newValue):
以原子方式设置为 newValue 的值,并返回旧值。
下面源码演示基本类型的原子操作类:
public class UseAtomicInt {
static AtomicInteger ai = new AtomicInteger(10);
public static void main(String[] args) {
ai.getAndIncrement();
ai.incrementAndGet();
//ai.compareAndSet();
ai.addAndGet(24);
ai.getAndAdd(24);
}
}
主要是提供原子的方式更新数组里的整型,其常用方法如下。
-
int addAndGet(int i,int delta):以原子方式将输入值与数组中索引 i 的元 素相加。
-
boolean compareAndSet(int i,int expect,int update):如果当前值等于 预期值,则以原子方式将数组位置 i 的元素设置成 update 值。
需要注意的是,数组 value 通过构造方法传递进去,然后AtomicIntegerArray 会将当前数组复制一份,所以当 AtomicIntegerArray 对内部的数组元素进行修改 时,不会影响传入的数组。
原子更新基本类型的 AtomicInteger,只能更新一个变量,如果要原子更新多个变量,就需要使用这个原子更新引用类型提供的类。Atomic 包提供了以下 3 个类。
3.3.1、AtomicReference
原子更新引用类型:
public class UseAtomicReference {
static AtomicReference<UserInfo> atomicUserRef;
public static void main(String[] args) {
UserInfo user = new UserInfo("Mark", 15);//要修改的实体的实例
atomicUserRef = new AtomicReference(user);
UserInfo updateUser = new UserInfo("Bill",17);
atomicUserRef.compareAndSet(user,updateUser);
System.out.println(atomicUserRef.get());
System.out.println(user);
}
//定义一个实体类
static class UserInfo {
private volatile String name;
private int age;
public UserInfo(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
@Override
public String toString() {
return "UserInfo{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
}
3.3.2、AtomicStampedReference
利用版本戳的形式记录了每次改变以后的版本号,这样的话就不会存在 ABA 问题了。这就是 AtomicStampedReference 的解决方案。AtomicMarkableReference 跟 AtomicStampedReference 差不多,AtomicStampedReference 是使用 pair 的 int stamp 作为计数器使用,AtomicMarkableReference 的 pair 使用的是 boolean mark。 还是那个水的例子,AtomicStampedReference 可能关心的是动过几次, AtomicMarkableReference 关心的是有没有被人动过,方法都比较简单。
public class UseAtomicStampedReference {
static AtomicStampedReference<String> asr
= new AtomicStampedReference("mark",0);
public static void main(String[] args) throws InterruptedException {
//拿到当前的版本号(旧)
final int oldStamp = asr.getStamp();
final String oldReference = asr.getReference();
System.out.println(oldReference+"============"+oldStamp);
Thread rightStampThread = new Thread(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+":当前变量值:"
+oldReference + "-当前版本戳:" + oldStamp + "-"
+ asr.compareAndSet(oldReference,
oldReference + "+Java", oldStamp,
oldStamp + 1));
}
});
Thread errorStampThread = new Thread(new Runnable() {
@Override
public void run() {
String reference = asr.getReference();
System.out.println(Thread.currentThread().getName()
+":当前变量值:"
+reference + "-当前版本戳:" + asr.getStamp() + "-"
+ asr.compareAndSet(reference,
reference + "+C", oldStamp,
oldStamp + 1));
}
});
rightStampThread.start();
rightStampThread.join();
errorStampThread.start();
errorStampThread.join();
System.out.println(asr.getReference()+"============"+asr.getStamp());
}
}
3.3.3、AtomicMarkableReference
AtomicMarkableReference:
原子更新带有标记位的引用类型。可以原子更新一个布尔类型的标记位和引 用类型。构造方法是 AtomicMarkableReference(V initialRef,booleaninitialMark)。
Java高频面试专题合集解析:
当然在这还有更多整理总结的Java进阶学习笔记和面试题未展示,其中囊括了Dubbo、Redis、Netty、zookeeper、Spring cloud、分布式、高并发等架构资料和完整的Java架构学习进阶导图!
更多Java架构进阶资料展示
当然在这还有更多整理总结的Java进阶学习笔记和面试题未展示,其中囊括了Dubbo、Redis、Netty、zookeeper、Spring cloud、分布式、高并发等架构资料和完整的Java架构学习进阶导图!
[外链图片转存中…(img-lMw7Fith-1721161178854)]
更多Java架构进阶资料展示
[外链图片转存中…(img-WrEZKFKR-1721161178854)]
[外链图片转存中…(img-c821wz7l-1721161178854)]
[外链图片转存中…(img-k1BGDUIb-1721161178855)]