Juc15_基本AtomicInteger数组引用AtomicStampedReference对象的属性修改原子类AtomicIntegerFieldUp 原子操作增强类LongAdder
Posted TZ845195485
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Juc15_基本AtomicInteger数组引用AtomicStampedReference对象的属性修改原子类AtomicIntegerFieldUp 原子操作增强类LongAdder相关的知识,希望对你有一定的参考价值。
接下来我们会去介绍18罗汉以及LongAdder底层实现原理
(1). 基本类型原子类(AtomicInteger、AtomicBoolean、AtomicLong)
(2). 数组类型原子类 (AtomicIntegerArray、AtomicLongArray、AtomicReferenceArray)
(3). 引用类型原子类 (AtomicReference、AtomicStampedReference、AtomicMarkableReference)
(4). 对象的属性修改原子类 (AtomicIntegerFieldUp dater、AtomicLongFieldUpdater、AtomicRefere nceFieldUpdater)
(5). 原子操作增强类(DoubleAccumulator 、DoubleAdder 、LongAccumulator 、LongAdder)
(6). 第17位罗汉:Striped64 第18位罗汉: Number
文章目录
- ①. atomic是什么?
- ②. 基本类型原子类(AtomicInteger、AtomicBoolean、AtomicLong)
- ③. 数组类型原子类 (AtomicIntegerArray、AtomicLongArray、AtomicReferenceArray)
- ④. 引用类型原子类 (AtomicReference、AtomicStampedReference、AtomicMarkableReference)
- ⑤. 对象的属性修改原子类 (AtomicIntegerFieldUp dater、AtomicLongFieldUpdater、AtomicRefere nceFieldUpdater)
- ⑥. 原子操作增强类(DoubleAccumulator 、DoubleAdder 、LongAccumulator 、LongAdder)
①. atomic是什么?
- ①. atomic是原子类,主要有如下:
- ②. Java开发手册中说明:
②. 基本类型原子类(AtomicInteger、AtomicBoolean、AtomicLong)
- ①. 常用API简介
方法 | 解释 |
---|---|
public final int get() | 获取当前的值 |
public final int getAndSet(int newValue) | 获取到当前的值,并设置新的值 |
public final int getAndIncrement() | 获取当前的值,并自增 |
public final int getAndDecrement() | 获取到当前的值,并自减 |
public final int getAndAdd(int delta) | 获取到当前的值,并加上预期的值 |
public final int incrementAndGet( ) | 返回的是加1后的值 |
boolean compareAndSet(int expect,int update) | 如果输入的数值等于预期值,返回true |
- ②. AtomicInteger解决 i++ 多线程下不安全问题
CountDownLatch如何在程序中使用
public class AtomicIntegerDemo {
AtomicInteger atomicInteger=new AtomicInteger(0);
public void addPlusPlus(){
atomicInteger.incrementAndGet();
}
public static void main(String[] args) throws InterruptedException {
CountDownLatch countDownLatch=new CountDownLatch(10);
AtomicIntegerDemo atomic=new AtomicIntegerDemo();
// 10个线程进行循环100次调用addPlusPlus的操作,最终结果是10*100=1000
for (int i = 1; i <= 10; i++) {
new Thread(()->{
try{
for (int j = 1; j <= 100; j++) {
atomic.addPlusPlus();
}
}finally {
countDownLatch.countDown();
}
},String.valueOf(i)).start();
}
//(1). 如果不加上下面的停顿3秒的时间,会导致还没有进行i++ 1000次main线程就已经结束了
//try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) {e.printStackTrace();}
//(2). 使用CountDownLatch去解决等待时间的问题
countDownLatch.await();
System.out.println(Thread.currentThread().getName()+"\\t"+"获取到的result:"+atomic.atomicInteger.get());
}
}
- ③. AtomicBoolean可以作为中断标识停止线程的方式
//线程中断机制的实现方法
public class AtomicBooleanDemo {
public static void main(String[] args) {
AtomicBoolean atomicBoolean=new AtomicBoolean(false);
new Thread(()->{
System.out.println(Thread.currentThread().getName()+"\\t"+"coming.....");
while(!atomicBoolean.get()){
System.out.println("==========");
}
System.out.println(Thread.currentThread().getName()+"\\t"+"over.....");
},"A").start();
new Thread(()->{
atomicBoolean.set(true);
},"B").start();
}
}
- ④. AtomicLong的底层是CAS+自旋锁的思想,适用于低并发的全局计算,高并发后性能急剧下降,原因如下:N个线程CAS操作修改线程的值,每次只有一个成功过,其他N-1失败,失败的不停的自旋直到成功,这样大量失败自旋的情况,一下子cpu就打高了(AtomicLong的自旋会成为瓶颈)
在高并发的情况下,我们使用LoadAdder
③. 数组类型原子类 (AtomicIntegerArray、AtomicLongArray、AtomicReferenceArray)
-
①. 数组类型原子类,主要有三个AtomicIntegerArray、AtomicLongArray、AtomicReferenceArray
(了解即可) -
②. 代码展示
public class AtomicIntegerArrayDemo {
public static void main(String[] args) {
//(1). 创建一个新的AtomicIntegerArray,其长度与从给定数组复制的所有元素相同。
int[]arr2={1,2,3,4,5};
AtomicIntegerArray array=new AtomicIntegerArray(arr2);
//(2). 创建给定长度的新AtomicIntegerArray,所有元素最初为零。
//AtomicIntegerArray array=new AtomicIntegerArray(5);
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i]);
}
System.out.println();
System.out.println("=======");
array.getAndSet(0,1111);
System.out.println("============");
System.out.println("将数字中位置为0位置上的元素改为:"+array.get(0));
System.out.println("数组位置为1位置上的旧值是:"+array.get(1));
System.out.println("将数组位置为1位置上的数字进行加1的处理");
array.getAndIncrement(1);
System.out.println("数组位置为1位置上的新值是:"+array.get(1));
}
}
④. 引用类型原子类 (AtomicReference、AtomicStampedReference、AtomicMarkableReference)
-
①. 引用类型原子类主要有三个: AtomicReference、AtomicStampedReference、AtomicMark ableReference
-
②. 使用AtomicReference来实现自旋锁案例
//自旋锁
public class AtomicReferenceThreadDemo {
static AtomicReference<Thread>atomicReference=new AtomicReference<>();
static Thread thread;
public static void lock(){
thread=Thread.currentThread();
System.out.println(Thread.currentThread().getName()+"\\t"+"coming.....");
while(!atomicReference.compareAndSet(null,thread)){
}
}
public static void unlock(){
System.out.println(Thread.currentThread().getName()+"\\t"+"over.....");
atomicReference.compareAndSet(thread,null);
}
public static void main(String[] args) {
new Thread(()->{
AtomicReferenceThreadDemo.lock();
try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) {e.printStackTrace();}
AtomicReferenceThreadDemo.unlock();
},"A").start();
new Thread(()->{
AtomicReferenceThreadDemo.lock();
AtomicReferenceThreadDemo.unlock();
},"B").start();
}
}
- ③. AtomicStampedReference 解决ABA问题
- 携带版本号的引用类型原子类,可以解决ABA问题
- 解决修改过几次
- 状态戳原子引用
/**
* Description: ABA问题的解决
*
* @author TANGZHI
* @date 2021-03-26 21:30
**/
public class ABADemo {
private static AtomicReference<Integer> atomicReference=new AtomicReference<>(100);
private static AtomicStampedReference<Integer> stampedReference=new AtomicStampedReference<>(100,1);
public static void main(String[] args) {
System.out.println("===以下是ABA问题的产生===");
new Thread(()->{
atomicReference.compareAndSet(100,101);
atomicReference.compareAndSet(101,100);
},"t1").start();
new Thread(()->{
//先暂停1秒 保证完成ABA
try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }
System.out.println(atomicReference.compareAndSet(100, 2019)+"\\t"+atomicReference.get());
},"t2").start();
try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); }
System.out.println("===以下是ABA问题的解决===");
new Thread(()->{
int stamp = stampedReference.getStamp();
System.out.println(Thread.currentThread().getName()+"\\t 第1次版本号"+stamp+"\\t值是"+stampedReference.getReference());
//暂停1秒钟t3线程
try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }
stampedReference.compareAndSet(100,101,stampedReference.getStamp(),stampedReference.getStamp()+1);
System.out.println(Thread.currentThread().getName()+"\\t 第2次版本号"+stampedReference.getStamp()+"\\t值是"+stampedReference.getReference());
stampedReference.compareAndSet(101,100,stampedReference.getStamp(),stampedReference.getStamp()+1);
System.out.println(Thread.currentThread().getName()+"\\t 第3次版本号"+stampedReference.getStamp()+"\\t值是"+stampedReference.getReference());
},"t3").start();
new Thread(()->{
int stamp = stampedReference.getStamp();
System.out.println(Thread.currentThread().getName()+"\\t 第1次版本号"+stamp+"\\t值是"+stampedReference.getReference());
//保证线程3完成1次ABA
try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); }
boolean result = stampedReference.compareAndSet(100, 2019, stamp, stamp + 1);
System.out.println(Thread.currentThread().getName()+"\\t 修改成功否"+result+"\\t最新版本号"+stampedReference.getStamp());
System.out.println("最新的值\\t"+stampedReference.getReference());
},"t4").start();
}
- ④. AtomicMarkableReference 不建议用它解决ABA问题
- 原子更新带有标志位的引用类型对象
- 解决是否修改(它的定义就是将状态戳简化位true|false),类似一次性筷子
- 状态戳(true/false)原子引用
- 不建议用它解决ABA问题
public class ABADemo{
static AtomicMarkableReference<Integer> markableReference = new AtomicMarkableReference<>(100,false);
public static void main(String[] args){
System.out.println("============AtomicMarkableReference不关心引用变量更改过几次,只关心是否更改过======================");
new Thread(() -> {
boolean marked = markableReference.isMarked();
System.out.println(Thread.currentThread().getName()+"\\t 1次版本号"+marked);
try { TimeUnit.MILLISECONDS.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); }
markableReference.compareAndSet(100,101,marked,!marked);
System.out.println(Thread.currentThread().getName()+"\\t 2次版本号"+markableReference.isMarked());
markableReference.compareAndSet(101,100,markableReference.isMarked(),!markableReference.isMarked());
System.out.println(Thread.currentThread().getName()+"\\t 3次版本号"+markableReference.isMarked());
},"线程A").start();
new Thread(() -> {
boolean marked = markableReference.isMarked();
System.out.println(Thread.currentThread().getName()+"\\t 1次版本号"+marked);
//暂停几秒钟线程
try { TimeUnit.MILLISECONDS.sleep(100); } catch (InterruptedException e) { e.printStackTrace()以上是关于Juc15_基本AtomicInteger数组引用AtomicStampedReference对象的属性修改原子类AtomicIntegerFieldUp 原子操作增强类LongAdder的主要内容,如果未能解决你的问题,请参考以下文章
JUC并发编程 -- 原子整数(AtomicInteger)& 原子引用 (介绍 & ABA问题 & AtomicStampedReference & AtomicMa