1. CAS
compare and swap,比较并交换。
包含三个操作数:内存位置、预期原值及更新值。
执行CAS操作的时候,将内存位置的值与预期原值比较:
- 匹配,更新为新值。
- 不匹配,不进行操作,多个线程同时执行CAS操作只有一个会成功。
CAS是JDK提供的非阻塞原子性操作,通过硬件保证比较-更新的原子性。底层实现为CPU指令cmpxchg,效率更高。通过unsafe类实现。
2. 自旋
线程修改失败重试的过程叫自旋。
java">public static void main(String[] args) {AtomicInteger integer = new AtomicInteger(5);System.out.println(integer.compareAndSet(51, 200) + " " + integer.get());}
自旋的实现代码
自己实现一个CAS。
java">public class SingletonLock {AtomicReference<Thread> atomicThread = new AtomicReference<>();public void Lock() {Thread thread = Thread.currentThread();System.out.println(thread.getName() + "Lock");// 当前不为空, 需要进行自旋while (!atomicThread.compareAndSet(null, thread)) {}}public void unLock() {Thread thread = Thread.currentThread();System.out.println(thread.getName() + "unLock");atomicThread.compareAndSet(thread, null);}public static void main(String[] args) {SingletonLock singletonLock = new SingletonLock();new Thread(()->{singletonLock.Lock();try {TimeUnit.SECONDS.sleep(2);} catch (InterruptedException e) {throw new RuntimeException(e);}singletonLock.unLock();}, "t1").start();try {TimeUnit.MILLISECONDS.sleep(200);} catch (InterruptedException e) {throw new RuntimeException(e);}new Thread(()->{singletonLock.Lock();singletonLock.unLock();}, "t2").start();}
}
3. AtomicReference包装类
java">class Stu {String name;Integer age;public Stu(String name, Integer age) {this.name = name;this.age = age;}@Overridepublic String toString() {return name + ": " + age;}
}public class demo03 {public static void main(String[] args) {Stu zs = new Stu("zs", 18);Stu ls = new Stu("ls", 29);AtomicReference<Stu> atomicReference = new AtomicReference<>();atomicReference.set(zs);System.out.println(atomicReference.compareAndSet(zs, ls) + " " + atomicReference.get().toString());}
}
4. CAS缺点
4.1 循环时间长,开销大
4.2 ABA问题
解决方案:版本号,戳记流水。
java">class Stus {Integer id;String name;public Stus(Integer id, String name) {this.id = id;this.name = name;}public String getName() {return name;}
}
public class demo04 {public static void main(String[] args) {Stus zs = new Stus(1, "zs");Stus ls = new Stus(2, "ls");AtomicStampedReference<Stus> atomicStampedReference = new AtomicStampedReference<>(zs, 1);atomicStampedReference.compareAndSet(zs, ls, atomicStampedReference.getStamp(), 2);System.out.println(atomicStampedReference.getReference().getName());atomicStampedReference.compareAndSet(ls,zs, atomicStampedReference.getStamp(), 3);System.out.println(atomicStampedReference.getReference().getName());}
}