之前讲到 volatile 关键字,只能保证变量的可见性和有序性
要想保证其原子性,则需要用到 Java 并发包下面的原子类
原子类的方法都是调用 Unsafe 的 cas 方法,cas 其实是操作系统底层的一条原语指令
但是原子类只能保证单个变量的原子性,这个时候想保证自定义对象的原子性,就需要用到原子引用类
1. AtomicReference<T>
泛型,接收一个类作为原子类型引用
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
class Book{
String name;
int price;
public Book(String name, int price){
this.name = name;
this.price = price;
}
}
public class AtomicReferenceDemo {
static AtomicReference<Book> atomicReference = new AtomicReference<>(new Book("z3", 100));
public static void main(String[] args) {
new Thread(()->{
Book z3 = atomicReference.get();
System.out.println(Thread.currentThread().getName()+"\t"+"当前书名字 = "+z3.name+" 当前书价格 = "+z3.price);
try{ TimeUnit.SECONDS.sleep(1);}catch (InterruptedException e){e.printStackTrace();}
atomicReference.compareAndSet(z3, new Book("l4",200));
},"t1").start();
new Thread(()->{
Book z3 = atomicReference.get();
System.out.println(Thread.currentThread().getName()+"\t"+"当前书名字 = "+z3.name+" 当前书价格 = "+z3.price);
try{ TimeUnit.SECONDS.sleep(1);}catch (InterruptedException e){e.printStackTrace();}
boolean l4 = atomicReference.compareAndSet(z3, new Book("w5", 500));
System.out.println(Thread.currentThread().getName()+"\t"+"修改结果:"+l4);
System.out.println("当前书的名字="+atomicReference.get().name+" "+"当前书的价格为:"+atomicReference.get().price);
},"t2").start();
}
}
2. AtomicMarkableReference
记录当前值是否被修改过: true / false
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicMarkableReference;
public class AtomicMarkableReferenceDemo {
static AtomicMarkableReference markedAbleReference = new AtomicMarkableReference<>(100,false);
public static void main(String[] args) {
new Thread(()->{
boolean marked = markedAbleReference.isMarked();
System.out.println(Thread.currentThread().getName()+"\t"+"默认标识符:"+marked);
try{TimeUnit.SECONDS.sleep(1);}catch (InterruptedException e){e.printStackTrace();}
markedAbleReference.compareAndSet(100,1000,marked,!marked);
},"t1").start();
new Thread(()->{
boolean marked = markedAbleReference.isMarked();
System.out.println(Thread.currentThread().getName()+"\t"+"默认标识符:"+marked);
try{TimeUnit.SECONDS.sleep(2);}catch (InterruptedException e){e.printStackTrace();}
boolean b = markedAbleReference.compareAndSet(100, 2000, marked, !marked);
System.out.println(Thread.currentThread().getName()+"\t"+"操作结果:"+b);
System.out.println(Thread.currentThread().getName()+"\t"+"markedAbleReference:"+markedAbleReference.isMarked());
System.out.println(Thread.currentThread().getName()+"\t"+"引用值:"+markedAbleReference.getReference());
},"t2").start();
}
}
3. AtomicStampeReference 带版本戳号的原子引用类
每个线程修改之后都更新版本号,在每一个线程使用cas方法提交更新时,都必须比较值和版本号
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicStampedReference;
public class AtomicStampedReferenceDemo {
static AtomicStampedReference<String> atomicStampedReference = new AtomicStampedReference<>("hello",1);
public static void main(String[] args) {
new Thread(()->{
int stampe = atomicStampedReference.getStamp();
String reference = atomicStampedReference.getReference();
System.out.println(Thread.currentThread().getName()+"\t"+"当前版本戳 = "+stampe+" 当前值内容为 = "+reference);
try{ TimeUnit.SECONDS.sleep(1);}catch (InterruptedException e){e.printStackTrace();}
atomicStampedReference.compareAndSet("hello","t1-hello",1,2);
},"t1").start();
new Thread(()->{
int stampe = atomicStampedReference.getStamp();
String reference = atomicStampedReference.getReference();
System.out.println(Thread.currentThread().getName()+"\t"+"当前版本戳 = "+stampe+" 当前值内容为 = "+reference);
try{ TimeUnit.SECONDS.sleep(2);}catch (InterruptedException e){e.printStackTrace();}
boolean b = atomicStampedReference.compareAndSet("hello", "t2-hello", 1, 2);
System.out.println(Thread.currentThread().getName()+"\t"+"修改是否成功: "+b);
System.out.println(Thread.currentThread().getName()+"\t"
+"修改后当前版本戳 = "+atomicStampedReference.getStamp()
+" 修改后当前值内容为 = "+atomicStampedReference.getReference());
},"t2").start();
}
}