欢迎您的访问
专注于Java技术系列文章的Java技术分享网站

多线程笔记 二:原子操作

什么是原子操作

不可被中断的一个或者一系列操作

实现原子操作的方式

Java可以通过锁和循环CAS的方式实现原子操作

CAS( Compare And Swap ) 为什么要有CAS?

Compare And Swap就是比较并且交换的一个原子操作,由Cpu在指令级别上进行保证。

为什么要有CAS:因为通过锁实现原子操作时,其他线程必须等待已经获得锁的线程运行完以后才能获得资源,这样就会占用系统的大量资源

CAS包含哪些参数?

CAS包含三个参数:1、变量所在内存地址V;2、变量对应的值A;3、我们将要修改的值B。如果说V上的变量的值是A的话,就用B重新赋值,如果不是A,那就什么事也不做,操作的返回结果原值是多少。

循环CAS:在一个(死)循环【for(;;)】里不断进行CAS操作,直到成功为止(自旋操作即死循环)。

CAS****实现原子操作的三大问题

1、 ABA问题:其他的线程把值改成了B,很快改成了A,原子操作的线程发现值是A就修改,这样会有问题。解决ABA,引入版本号:1A-》2C-》3A

2、 循环时间很长的话,cpu的负荷比较大

3、 对一个变量进行操作可以,同时操作多个共享变量有点麻烦

CAS线程安全****(****面试点****)

通过硬件层面的阻塞实现原子操作的安全

原子更新基本类型类

AtomicBoolean、AtomicInteger、AtomicLong、AtomicReference。

AtomicInteger的常用方法如下

·int addAndGet(int delta):

·boolean compareAndSet(int expect,int update):

·int getAndIncrement(): 原子递增,但是返回的是自增以前的值

incrementAndGet原子递增,但是返回的是自增以后的值

·int getAndSet(int newValue):

 package com.lgs.atomicint;

 import java.util.concurrent.atomic.AtomicInteger;

 /**
  * lgs
  * 原子操作更新整型
  */
 public class AtomicIntTest {
     static AtomicInteger ai = new AtomicInteger(1);
     public static void main(String[] args) {
         System.out.println(ai.getAndIncrement());
         ai.incrementAndGet();
         System.out.println(ai.get());
     }
 }

输出:

1
3

原子更新数组类

AtomicIntegerArray,AtomicLongArray,AtomicReferenceArray

AtomicIntegerArray类主要是提供原子的方式更新数组里的整型,

其常用方法如下。

·int addAndGet(int i,int delta):

·boolean compareAndSet(int i,int expect,int update):

数组通过构造方法传入,类会将数组复制一份,原数组不会发生变化。

 package com.lgs.atomicarray;

 import java.util.concurrent.atomic.AtomicIntegerArray;

 /**
  * lgs
  * 原子操作更新数组
  */
 public class AtomicArray {
     static int[] value = new int[]{1,2};
     static AtomicIntegerArray ai = new AtomicIntegerArray(value);

     public static void main(String[] args) {
         ai.getAndSet(0,3);
         System.out.println(ai.get(0));
         System.out.println(value[0]);
     }

 }

输出:

3
1

原子更新引用类型提供的类。

·AtomicReference: 可以解决更新多个变量的问题

·AtomicStampedReference:解决ABA问题 使用数字作为版本 关心得是有几个人改过

·AtomicMarkableReference:解决ABA问题 使用Boolean作为版本,关心的是有没有修改过

 package com.lgs;

 import java.util.concurrent.atomic.AtomicReference;

 /**
  * lgs
  * 原子操作更新引用类型即可以同时更新多个值
  */
 public class AtomicRef {

     static AtomicReference<User> userAtomicReference = new AtomicReference<>();

     public static void main(String[] args) {
         User user = new User("lgs",26);
         userAtomicReference.set(user);
         User updateUser = new User("ll",27);
         userAtomicReference.compareAndSet(user,updateUser);
         System.out.println(userAtomicReference.get().getName());
         System.out.println(userAtomicReference.get().getOld());
     }

     static class User{
         private String name;
         private int old;

         public User(String name, int old) {
             this.name = name;
             this.old = old;
         }

         public String getName() {
             return name;
         }

         public int getOld() {
             return old;
         }
     }

 }

输出:

ll
27

原子更新字段类

Atomic包提供了以下3个类进行原子字段更新。

·AtomicReferenceFieldUpdater:

·AtomicIntegerFieldUpdater:

·AtomicLongFieldUpdater:

违反了面向对象的原则,一般不使用

来源:https://www.cnblogs.com/leeSmall/category/1143351.html

文章永久链接:https://tech.souyunku.com/?p=14366

赞(94) 打赏



版权归原创作者所有,任何形式转载请联系作者;搜云库 » 多线程笔记 二:原子操作

本站:免责声明!

评论 抢沙发

一个专注于Java技术系列文章的技术分享网站

觉得文章有用就打赏一下文章作者

微信扫一扫打赏

微信扫一扫打赏