java多线程 -- 原子量 变量 CAS

简介: 多线程原子性问题的产生和解决原子变量:在 java.util.concurrent.atomic 包下提供了一些原子变量。1. volatile 保证内存可见性,可以查看atomic中变量是使用volatile来进行修饰的: public class AtomicInteger extends Number implements java.

多线程原子性问题的产生和解决

原子变量:在 java.util.concurrent.atomic 包下提供了一些原子变量。

1. volatile 保证内存可见性,可以查看atomic中变量是使用volatile来进行修饰的:

 

public class AtomicInteger extends Number implements java.io.Serializable {
    private static final long serialVersionUID = 6214790243416807050L;

    // setup to use Unsafe.compareAndSwapInt for updates
    private static final Unsafe unsafe = Unsafe.getUnsafe();
    private static final long valueOffset;

    static {
        try {
            valueOffset = unsafe.objectFieldOffset
                (AtomicInteger.class.getDeclaredField("value"));
        } catch (Exception ex) { throw new Error(ex); }
    }

    private volatile int value;

    /**
     * Creates a new AtomicInteger with the given initial value.
     *
     * @param initialValue the initial value
     */
    public AtomicInteger(int initialValue) {
        value = initialValue;
    }

2. CAS(Compare-And-Swap)比较并交换,算法保证数据变量的原子性
 CAS 算法是硬件对于并发操作的支持
 CAS 包含了三个操作数:
 ①内存值 V
 ②预估值 A
 ③更新值 B
 当且仅当 V == A 时, V = B; 否则,不会执行任何操作。

模拟CAS算法:

/*
 * 模拟 CAS 算法
 */
public class TestCompareAndSwap {

    public static void main(String[] args) {
        final CompareAndSwap cas = new CompareAndSwap();
        
        for (int i = 0; i < 10; i++) {
            new Thread(new Runnable() {
                
                @Override
                public void run() {
                    int expectedValue = cas.get();
                    boolean b = cas.compareAndSet(expectedValue, (int)(Math.random() * 101));
                    System.out.println(b);
                }
            }).start();
        }
        
    }
    
}

class CompareAndSwap{
    private int value;
    
    //获取内存值
    public synchronized int get(){
        return value;
    }
    
    //比较
    public synchronized int compareAndSwap(int expectedValue, int newValue){
        int oldValue = value;
        
        if(oldValue == expectedValue){
            this.value = newValue;
        }
        
        return oldValue;
    }
    
    //设置
    public synchronized boolean compareAndSet(int expectedValue, int newValue){
        return expectedValue == compareAndSwap(expectedValue, newValue);
    }
}

 

其他博文关于CAS的详细描述:http://blog.csdn.net/ls5718/article/details/52563959

  1. AtomicBoolean 可以用原子方式更新的 boolean 值。
  2. AtomicInteger 可以用原子方式更新的 int 值。
  3. AtomicIntegerArray 可以用原子方式更新其元素的 int 数组。
  4. AtomicIntegerFieldUpdater<T> 基于反射的实用工具,可以对指定类的指定 volatile int 字段进行原子更新。
  5. AtomicLong 可以用原子方式更新的 long 值。
  6. AtomicLongArray 可以用原子方式更新其元素的 long 数组。
  7. AtomicLongFieldUpdater<T> 基于反射的实用工具,可以对指定类的指定 volatile long 字段进行原子更新。
  8. AtomicMarkableReference<V> AtomicMarkableReference 维护带有标记位的对象引用,可以原子方式对其进行更新。
  9. AtomicReference<V> 可以用原子方式更新的对象引用。
  10. AtomicReferenceArray<E> 可以用原子方式更新其元素的对象引用数组。
  11. AtomicReferenceFieldUpdater<T,V> 基于反射的实用工具,可以对指定类的指定 volatile 字段进行原子更新。
  12. AtomicStampedReference<V> AtomicStampedReference 维护带有整数“标志”的对象引用,可以用原子方式对其进行更新。

先看下AtomicInteger:

import java.util.concurrent.atomic.AtomicInteger;

/**
 * Created by soyoungboy on 2017/3/28.
 */
public class AtomicDemo {
    public static void main(String[] args) {
        testAtomicInteger();
    }

    private static void testAtomicInteger() {
        AtomicInteger atomicInteger = new AtomicInteger(1);
        //get()获取当前值。
        int x = atomicInteger.get();
        System.out.println("get()获取当前值 = " + x);
        //addAndGet(int delta)以原子方式将给定值与当前值相加
        int i = atomicInteger.addAndGet(2);
        System.out.println("addAndGet(int delta)以原子方式将给定值与当前值相加 = " + i);
        // decrementAndGet()以原子方式将当前值减 1。
        int i1 = atomicInteger.decrementAndGet();
        System.out.println("decrementAndGet()以原子方式将当前值减 1 = " + i1);
        //doubleValue() 以 double 形式返回指定的数值。
        double doubleValue = atomicInteger.doubleValue();
        System.out.println("doubleValue() 以 double 形式返回指定的数值。 = " + doubleValue);
        //floatValue()以 float 形式返回指定的数值。
        float floatValue = atomicInteger.floatValue();
        System.out.println("floatValue()以 float 形式返回指定的数值。。 = " + floatValue);
        // intValue() 以 int 形式返回指定的数值。
        int intValue = atomicInteger.intValue();
        System.out.println("intValue() 以 int 形式返回指定的数值。= " + intValue);
        //etAndSet(int newValue)以原子方式设置为给定值,并返回旧值。
        int andAdd = atomicInteger.getAndAdd(20);
        System.out.println("---------------------------------------------------------");
        System.out.println("getAndAdd(int delta)以原子方式将给定值与当前值相加。旧值 = " + andAdd);
        System.out.println("新值 = " + atomicInteger.get());
        System.out.println("---------------------------------------------------------");
        //getAndDecrement()以原子方式将当前值加 1。
        int andDecrement = atomicInteger.getAndDecrement();
        System.out.println("getAndDecrement()以原子方式将当前值减 1。 = " + andDecrement);
        //getAndDecrement()以原子方式将当前值减 1。
        int andIncrement = atomicInteger.getAndIncrement();
        System.out.println("getAndDecrement()以原子方式将当前值减 1。" + andIncrement);
        //以原子方式将当前值加 1。
        int incrementAndGet = atomicInteger.incrementAndGet();
        System.out.println("以原子方式将当前值加 1。" + incrementAndGet);

    }
}

 结果:

get()获取当前值 = 1
addAndGet(int delta)以原子方式将给定值与当前值相加 = 3
decrementAndGet()以原子方式将当前值减 1 = 2
doubleValue() 以 double 形式返回指定的数值。 = 2.0
floatValue()以 float 形式返回指定的数值。。 = 2.0
intValue() 以 int 形式返回指定的数值。= 2
---------------------------------------------------------
getAndAdd(int delta)以原子方式将给定值与当前值相加。旧值 = 2
新值 = 22
---------------------------------------------------------
getAndDecrement()以原子方式将当前值减 1。 = 22
getAndDecrement()以原子方式将当前值减 1。21
以原子方式将当前值加 1。23

 原子更新数组

  1. AtomicIntegerArray
  2. AtomicLongArray
  3. AtomicReferenceArray<E>
/**
 * Created by soyoungboy on 2017/3/28.
 */
public class AtomicDemo {
    public static void main(String[] args) {
        testAtomicInteger();
    }

    private static void testAtomicInteger() {
        Person person = new Person(11,"小强");
        Person person1 = new Person(11,"大强");
        Person[] peoples = new Person[]{person,person1};
        AtomicReferenceArray<Person> personAtomicReferenceArray = new AtomicReferenceArray<Person>(peoples);
        printArray(personAtomicReferenceArray);
        // 以原子方式将位置 i 的元素设置为给定值,并返回旧值。
        Person person2 = new Person(22, "老秦");
        Person andSet = personAtomicReferenceArray.getAndSet(1, person2);
        System.out.println("返回的旧值 = "+andSet);
        printArray(personAtomicReferenceArray);
        //weakCompareAndSet(int i, E expect, E update)
        // 如果当前值 == 预期值,则以原子方式将位置 i 的元素设置为给定的更新值。
        Person person3 = new Person(23, "哈哈");
        //因为上面替换为老秦的person,所以如果是老秦的person,就替换
        personAtomicReferenceArray.weakCompareAndSet(1,person2,person3);
        printArray(personAtomicReferenceArray);
    }


    private static void printArray(AtomicReferenceArray<Person> personAtomicReferenceArray) {
        System.out.println("-------------------------------------");
        for (int i = 0;i<personAtomicReferenceArray.length();i++){
            String s = personAtomicReferenceArray.get(i).toString();
            System.out.println(s);
        }
    }
}

结果:

-------------------------------------
Person{age=11, name='小强'}
Person{age=11, name='大强'}
返回的旧值 = Person{age=11, name='大强'}
-------------------------------------
Person{age=11, name='小强'}
Person{age=22, name='老秦'}
-------------------------------------
Person{age=11, name='小强'}
Person{age=23, name='哈哈'}

原子更新引用类型

  1. AtomicReference:原子更新引用类型。
  2. AtomicReferenceFieldUpdater:原子更新引用类型里的字段。
  3. AtomicMarkableReference:原子更新带有标记位的引用类型。可以原子更新一个布尔类型的标记位和引用类型。构造方法是AtomicMarkableReference(V initialRef,boolean initialMark)。

举例子:

import java.util.concurrent.atomic.AtomicReference;

/**
 * Created by Administrator on 2017/3/28.
 */
public class AtomicReferenceDemo {
    public static void main(String[] args) {
        testAtomicReference();
    }


    private static void testAtomicReference() {
        Person person1 = new Person(1,"姚明");
        Person person2 = new Person(2,"易建联");
        Person person3 = new Person(3,"王思聪");
        AtomicReference<Person> personAtomicReference = new AtomicReference<>(person1);
        System.out.println("personAtomicReference"+personAtomicReference.get().toString());
        System.out.println("------------------------------------------------------------");
        //compareAndSet(V expect, V update)如果当前值 == 预期值,则以原子方式将该值设置为给定的更新值。
        //person2肯定不是期望值,所以不会设置为person3,因此值应该为person1
        personAtomicReference.compareAndSet(person2,person3);
        System.out.println("personAtomicReference"+personAtomicReference.get().toString());
        System.out.println("------------------------------------------------------------");
        // getAndSet(V newValue) 以原子方式设置为给定值,并返回旧值。
        Person andSet = personAtomicReference.getAndSet(person2);
        System.out.println("旧值 = "+andSet);
        System.out.println("新值 = "+personAtomicReference.get().toString());
        personAtomicReference.lazySet(person3);
        //lazySet(V newValue)最终设置为给定值。
        System.out.println("lazySet  "+personAtomicReference.get().toString());
    }
}

结果:

personAtomicReferencePerson{age=1, name='姚明'}
------------------------------------------------------------
personAtomicReferencePerson{age=1, name='姚明'}
------------------------------------------------------------
旧值 = Person{age=1, name='姚明'}
新值 = Person{age=2, name='易建联'}
lazySet  Person{age=3, name='王思聪'}

 原子更新字段类

  1. AtomicIntegerFieldUpdater:原子更新整型的字段的更新器。
  2. AtomicLongFieldUpdater:原子更新长整型字段的更新器。
  3. AtomicStampedReference:原子更新带有版本号的引用类型。该类将整数值与引用关联起来,可用于原子的更新数据和数据的版本号,可以解决使用CAS进行原子更新时可能出现的ABA问题。

newUpdater(Class<U> tclass, String fieldName) 
          使用给定字段为对象创建和返回一个更新器。

这是这个不同于上面类的方法,其他基本上一样。

import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;

/**
 * Created by Administrator on 2017/3/28.
 */
public class AtomicIntegerFieldUpdaterDemo {
    public static void main(String[] args) {
        testAtomicReference();
    }


    private static void testAtomicReference() {
        Person person1 = new Person(1,"姚明");
        AtomicReferenceFieldUpdater<Person, String> atomicReferenceFieldUpdater = AtomicReferenceFieldUpdater.newUpdater(
            Person.class, String.class, "name");
        // 如果当前值 == 预期值,则以原子方式将此更新器管理的给定对象的字段设置为给定的更新值。
        atomicReferenceFieldUpdater.compareAndSet(person1,person1.name,"哈哈");
        System.out.println("person1  = "+person1.toString());

        AtomicReferenceFieldUpdater<Person, Integer> atomicReferenceFieldUpdater1 = AtomicReferenceFieldUpdater.newUpdater(
            Person.class, Integer.class, "age");
        // 如果当前值 == 预期值,则以原子方式将此更新器管理的给定对象的字段设置为给定的更新值。
        atomicReferenceFieldUpdater1.compareAndSet(person1,person1.age,22);
        System.out.println("person1  = "+person1.toString());

    }
}

结果:

person1  = Person{age=1, name='哈哈'}
person1  = Person{age=22, name='哈哈'}

 

相关文章
|
7月前
|
安全 算法 Java
Java 多线程:线程安全与同步控制的深度解析
本文介绍了 Java 多线程开发的关键技术,涵盖线程的创建与启动、线程安全问题及其解决方案,包括 synchronized 关键字、原子类和线程间通信机制。通过示例代码讲解了多线程编程中的常见问题与优化方法,帮助开发者提升程序性能与稳定性。
340 0
|
8月前
|
Java 数据挖掘 调度
Java 多线程创建零基础入门新手指南:从零开始全面学习多线程创建方法
本文从零基础角度出发,深入浅出地讲解Java多线程的创建方式。内容涵盖继承`Thread`类、实现`Runnable`接口、使用`Callable`和`Future`接口以及线程池的创建与管理等核心知识点。通过代码示例与应用场景分析,帮助读者理解每种方式的特点及适用场景,理论结合实践,轻松掌握Java多线程编程 essentials。
591 5
|
8月前
|
监控 搜索推荐 Java
Java 多线程最新实操技术与应用场景全解析:从基础到进阶
本文深入探讨了Java多线程的现代并发编程技术,涵盖Java 8+新特性,如CompletableFuture异步处理、Stream并行流操作,以及Reactive编程中的Reactor框架。通过具体代码示例,讲解了异步任务组合、并行流优化及响应式编程的核心概念(Flux与Mono)。同时对比了同步、CompletableFuture和Reactor三种实现方式的性能,并总结了最佳实践,帮助开发者构建高效、扩展性强的应用。资源地址:[点击下载](https://pan.quark.cn/s/14fcf913bae6)。
485 3
|
9月前
|
算法 Java 调度
Java多线程基础
本文主要讲解多线程相关知识,分为两部分。第一部分涵盖多线程概念(并发与并行、进程与线程)、Java程序运行原理(JVM启动多线程特性)、实现多线程的两种方式(继承Thread类与实现Runnable接口)及其区别。第二部分涉及线程同步(同步锁的应用场景与代码示例)及线程间通信(wait()与notify()方法的使用)。通过多个Demo代码实例,深入浅出地解析多线程的核心知识点,帮助读者掌握其实现与应用技巧。
159 1
|
9月前
|
安全 Java 程序员
【高薪程序员必看】万字长文拆解Java并发编程!(6-2):从CAS无锁机制到Atomic原子类实战指南
🌟 ​🌟今天给大家带来的是 ​💻⚡在这篇文章中,我们将一起探索:🔹 ​的底层原理,它是如何通过 ​实现无锁并发的?🔹 ​的终极对决,为什么高并发场景下CAS性能更优?🔹 ​的陷阱与解决方案——和实战演示!🔹 ​​(LongAdder等)的使用场景与性能对比🔹 危险的 ​黑魔法:为什么阿里禁止使用却又是并发库的基石?无论你是:✅ ​​(BATJ高频考点)✅ ​​(如何设计百万级计数器)✅ ​​(从Java代码到CPU指令的全链路分析)这篇文章都会让你收获满满!✨。
132 0
|
9月前
|
安全 Java 程序员
【高薪程序员必看】万字长文拆解Java并发编程!(6-1):从CAS无锁机制到Atomic原子类实战指南
🌟 ​🌟今天给大家带来的是 ​💻⚡在这篇文章中,我们将一起探索:🔹 ​的底层原理,它是如何通过 ​实现无锁并发的?🔹 ​的终极对决,为什么高并发场景下CAS性能更优?🔹 ​的陷阱与解决方案——和实战演示!🔹 ​​(LongAdder等)的使用场景与性能对比🔹 危险的 ​黑魔法:为什么阿里禁止使用却又是并发库的基石?无论你是:✅ ​​(BATJ高频考点)✅ ​​(如何设计百万级计数器)✅ ​​(从Java代码到CPU指令的全链路分析)这篇文章都会让你收获满满!✨。
136 0
|
9月前
|
Java
java 多线程异常处理
本文介绍了Java中ThreadGroup的异常处理机制,重点讲解UncaughtExceptionHandler的使用。通过示例代码展示了当线程的run()方法抛出未捕获异常时,JVM如何依次查找并调用线程的异常处理器、线程组的uncaughtException方法或默认异常处理器。文章还提供了具体代码和输出结果,帮助理解不同处理器的优先级与执行逻辑。
216 1
|
10月前
|
数据采集 存储 网络协议
Java HttpClient 多线程爬虫优化方案
Java HttpClient 多线程爬虫优化方案
|
11月前
|
存储 Java
# 【Java全栈学习笔记-U1-day02】变量+数据类型+运算符
本篇笔记主要围绕Java全栈学习的第二天内容展开,涵盖了变量、数据类型、运算符以及Scanner类的应用。首先介绍了变量的概念与命名规范,以及如何定义和使用变量;接着详细讲解了Java中的基本数据类型,包括整型、浮点型、字符型、布尔型等,并通过实例演示了数据类型的运用。随后,深入探讨了各类运算符(赋值、算术、关系、逻辑)及其优先级,帮助理解表达式的构成。最后,介绍了如何利用Scanner类实现用户输入功能,并通过多个综合示例(如计算圆面积、购物打折、变量交换及银行利息计算)巩固所学知识。完成相关作业将进一步加深对这些基础概念的理解与实践能力。
219 13
|
11月前
|
存储 网络协议 安全
Java网络编程,多线程,IO流综合小项目一一ChatBoxes
**项目介绍**:本项目实现了一个基于TCP协议的C/S架构控制台聊天室,支持局域网内多客户端同时聊天。用户需注册并登录,用户名唯一,密码格式为字母开头加纯数字。登录后可实时聊天,服务端负责验证用户信息并转发消息。 **项目亮点**: - **C/S架构**:客户端与服务端通过TCP连接通信。 - **多线程**:采用多线程处理多个客户端的并发请求,确保实时交互。 - **IO流**:使用BufferedReader和BufferedWriter进行数据传输,确保高效稳定的通信。 - **线程安全**:通过同步代码块和锁机制保证共享数据的安全性。
509 23

热门文章

最新文章