Java多线程八股(二),CAS详解,ReentrantLock和Synchronized的区别

目录:

一.CAS详解:

二.Callable接口,ReentrantLock和Synchronized的区别:

一.CAS详解:

1.什么是CAS:
CAS: 全称Compare and swap,字⾯意思:"比较并交换",⼀个 CAS 涉及到以下操作。
CAS本质上是操作系统的一个CPU指令,操作系统把这个指令进行封装,提供了一些API,可以被C++调用,JVM又基于 C++的实现,JVM也可以使用; 但是CAS指令我们一般不直接使用,而是使用JVM和标准库封装好的


2.CAS 伪代码:
下⾯写的代码不是原子的, 真实的 CAS 是⼀个原子的硬件指令完成的. 这个伪代码只是辅助理解 CAS的工作流程.
(这整个逻辑就相当于一条CPU指令, 值科学时才进行赋值,从而实现原子性的效果 )

java 复制代码
boolean CAS(address, expectValue, swapValue) {
 if (&address == expectedValue) {
 &address = swapValue;
 return true;
 }
 return false;
}

3.CAS 的应用:

应用一:实现原自类
标准库中提供了 java.util.concurrent.atomic 包, 里面的类都是基于这种方式来实现的.
典型的就是 AtomicInteger 类. 其中的 getAndIncrement 相当于 i++ 操作

使用代码:

java 复制代码
public class Demo {
    private static AtomicInteger count = new AtomicInteger();

    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(()->{
            for (int i = 0; i < 50000; i++) {

                //`getAndIncrement()` 会原子性地将当前值增加 1
                count.getAndIncrement();
            }
        });

        Thread t2 = new Thread(()->{
            for (int i = 0; i < 50000; i++) {

                //`getAndIncrement()` 会原子性地将当前值增加 1
                count.getAndIncrement();
            }
        });

        t1.start();
        t2.start();

        t1.join();
        t2.join();

        //`get()` 获取当前值。
        System.out.println(count.get());

    }
}

AtomicInteger 类CAS伪代码理解:

理解: value相当于内存,oldValue相当于寄存器

value==oldValue值就科学,直接返回oldValue,否则重新从内存拿值到寄存器重新判断值是否科学

java 复制代码
class AtomicInteger {
  private int value;//value理解为内存
  public int getAndIncrement() {
  int oldValue = value;
  while ( CAS(value, oldValue, oldValue+1) != true) {
   oldValue = value;//value==oldValue值就科学,直接返回oldValue,否则重新从内存拿值到寄存器重新判断值是否科学
  }
 return oldValue;
 }
}

应用二: 实现自旋锁

java 复制代码
public class SpinLock {
 private Thread owner = null;
 public void lock(){
 // 通过 CAS 看当前锁是否被某个线程持有. 
 // 如果这个锁已经被别的线程持有, 那么就⾃旋等待. 
 // 如果这个锁没有被别的线程持有, 那么就把 owner 设为当前尝试加锁的线程. 
 while(!CAS(this.owner, null, Thread.currentThread())){
 }
 }
 public void unlock (){
 this.owner = null;
 }
}

理解:owner == null,锁就没有被别的线程占有,直接返回

如果owner != null,该锁就被的线程占有,这时返回false,!取反置为true,继续往循环里走,但是这个循环没有东西,会进行"忙等"快速拿到别的线程抛弃的锁,这就是自旋锁


3.CAS 的 ABA 问题:

1.什么是ABA 问题,某个线程把内存的值修改为A,另一个线程把内存的值修改为B,又修改成原来的A (站在值科学的角度,最后为A,说明没有被其他线程修改过,实则不然只是被多修改了而已)

这样在极端情况可能会导致线程安全问题

(说起极端情况:闰秒问题也是服务器开发中的一个极端问题,就是某个时间点时间往前跳了导致代码逻辑上出现错误)

在取钱的时候,多个线程反复进行存钱(+)取钱(-)就可能出现转账余额问题(略)


2.解决:

这种ABA问题原因在于,有其他线程参与进来,进行加也进行减少余额,

想要避免这种ABA问题就要使用版本号,这个版本只进行加,另一个版本只进行减(每次修改一次,版本号就加1)



二.Callable接口,ReentrantLock和Synchronized的区别:

1.Callable接口和Runnable接口一样都可以超创建线程:

但是 Callable接口需要重写call方法,并且这个方法还有泛型的返回值


需要真正执行任务还不足以,因为Callable只定义了一个带有返回类型的任务,并没有真正执行 ,还需要搭配futureTask和Thread对象使用


代码:

java 复制代码
public static void main(String[] args) throws ExecutionException, InterruptedException {
        /** Callable只定义了一个带有返回类型的任务,并没有真正执行
         * 需要搭配futureTask和Thread对象使用
         *
         */
        Callable<Integer> callable = new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                int result = 0;
                for (int i = 0; i < 100; i++) {
                    result += i;
                }
                return result;
            }
        };

        FutureTask<Integer> futureTask = new FutureTask<>(callable);
        Thread t1 = new Thread(futureTask);
        t1.start();

        // get 操作就是获取到 FutureTask 的返回值. 这个返回值就来自于 Callable 的 call 方法.
        // get 可能会阻塞. 如果当前 线程 执行完毕, get 拿到返回结果.
        // 如果当前线程还没执行完毕, get 会一直阻塞.
        System.out.println(futureTask.get());

    }


2.ReentrantLock和Synchronized的区别:

(1).Synchronized是关键字, ReentrantLock是JVM内部通过C++实现的标准库的类

(2).Synchronized是通过代码块控制加锁解锁, **ReentrantLock**控制加锁解锁 是通过Lock和unLock方法控制的**(要注意unLock方法没有被执行到)**

(3). ReentrantLock除了还提供了****tryLock方法(加锁成功返回ture,加锁失败返回false,也有带次数的版本)

相关推荐
yyytucj2 分钟前
python--列表list切分(超详细)
linux·开发语言·python
等一场春雨13 分钟前
Java设计模式 八 适配器模式 (Adapter Pattern)
java·设计模式·适配器模式
肖田变强不变秃30 分钟前
C++实现有限元计算 矩阵装配Assembly类
开发语言·c++·矩阵·有限元·ansys
一弓虽35 分钟前
java基础学习——jdbc基础知识详细介绍
java·学习·jdbc·连接池
王磊鑫35 分钟前
Java入门笔记(1)
java·开发语言·笔记
喜欢猪猪43 分钟前
分布式与微服务:构建现代应用的关键架构
开发语言·php
硬件人某某某1 小时前
Java基于SSM框架的社区团购系统小程序设计与实现(附源码,文档,部署)
java·开发语言·社区团购小程序·团购小程序·java社区团购小程序
程序员徐师兄1 小时前
Java 基于 SpringBoot 的校园外卖点餐平台微信小程序(附源码,部署,文档)
java·spring boot·微信小程序·校园外卖点餐·外卖点餐小程序·校园外卖点餐小程序
kucupung1 小时前
【C++基础】多线程并发场景下的同步方法
开发语言·c++
chengpei1471 小时前
chrome游览器JSON Formatter插件无效问题排查,FastJsonHttpMessageConverter导致Content-Type返回不正确
java·前端·chrome·spring boot·json