CAS,ReentrantLock和synchronized总结

概念

CAS (compareAndSet(最新) 或compareAndSwap JDK不同版本名称不同)

当且仅当原值==期望值时,才更新为新值

具体表现为:

当一个线程需要修改某个值时,会将原值(即当前线程中该值的副本)跟主内存中的这个值进行比较,如果相等,就更新为新值.

例如 count++; 当前线程中count=2(原值); 主内存中的count=2(即期望值);此时count 就执行++操作,更新为count=3(新值)
如果此时当前线程中count=2(原值); 主内存中的count=3(即期望值);就不做任何操作.因为count=3就证明该值被其它线程改过
由此实现cas操作

为什么这么做:

是一种锁优化的形式,避免上重量级锁.

安全性思考:
  1. CAS操作本身会不会有线程安全问题?
    答:是CPU指令级的操作 不能被打断 所以不存在线程安全问题
  2. 如何解决ABA问题?
    答:加版本号控制

在JUC包下,凡是以Atomic开头的类都是用CAS操作保证线程安全,所以在实际开发中,例如遇到多线程递增计数需求时,可使用AtomicXXX等类提高多线程执行效率

ReentrantLock(可重入锁)与synchronized

其实跟sychronized 作用差不多,相当于是JDK1.5之后的sychronized 在JDK中的实现
本质上的区别在于sychronized 是JVM中的实现(不同的JVM,sychronized 的实现可以不同),ReentrantLock是JDK中的实现
在Java中,实现同步操作可以使用sychronized 或者Lock.lock(),Lock.unlock()两种方式锁住需要同步的代码块

但是在早期JDK版本中 加锁的操作是直接通过JVM通知操作系统使用内存屏障的原理进行控制 加锁操作直接进入内核态
后来的JDK对sychronized 进行了锁升级的优化,优化后的sychronized 操作步骤如下:

  1. 偏向锁 即 当前线程A进入同步代码块之后,会使用Mark Word标记该线程A已进入,以便后续线程进入时进行比较,如果还是A线程再次进入就不升级
  2. 自旋锁 即 当B线程进入时,此时偏向锁就会升级为自选锁,在等待A线程执行结束之前,会循环10次判断A线程是否执行完,超过10,锁升级
    偏向锁和自旋锁都是在JVM中完成的,都属于用户态
  3. 重量级锁 即 通过JVM通知操作系统进行线程调度 属于内核态

通过了解sychronized 的实现思路 对比ReentrantLock的实现
ReentrantLock就是将sychronized 的底层通过Java语言来实现 所以在实际开发使用当中 用法没有太大区别

所以使用ReentrantLock替代sychronized 是没问题的 就好比使用Lock.lock(),Lock.unlock()方式或sychronized 实现锁定同步代码块

ReentrantLock还有其它特性:

  1. tryLock 尝试锁,如果锁不住,可以执行哪些操作
  2. lockInterupptibly 打断锁
  3. 公平锁

ReentrantLock的实现原理:CAS
ReentrantLock与sychronized 的最大区别在于:ReentrantLock可以实现公平锁 而sychronized 是非公平的

公平与非公平锁

其实现主要依赖AQS(AbstractQueuedSynchronizer)这个类
原理:CAS 在AbstractQueuedSynchronizer维护了一个双向链表 和一个volatile修饰的state
公平锁:当新的线程进来时,进入双向链表,再进行state(本质上就是那把锁) 的竞争
非公平锁:当新的线程进来时,直接进入state 的竞争

JDK中其它使用CAS实现的锁

CountDownLatch 倒数门闩 用来等线程结束之后操作

CyclicBarrier N个线程满了 一起发车

Phaser 分段锁 遗传算法 分段栅栏 CyclicBarrier 升级版 颗粒度更细

ReadWriteLock 读写锁 即共享锁和排它锁

Semaphore 信号灯 限流 最多允许N个线程同时执行

Exchanger 交换器 线程之间交换变量值

LockSupport park()和unpark() 本质上和wait() notify() 一样

重点看下读写锁ReadWriteLock
import java.util.Random;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class ReadWriteLockTest {

    private static Lock lock = new ReentrantLock();
    private static int value;

    static ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
    static Lock readLock = readWriteLock.readLock();
    static Lock writeLock = readWriteLock.writeLock();

    public static void read(Lock lock) {
        try {
            lock.lock();
            Thread.sleep(1000);
            System.out.println("read over!");
            //模拟读取操作
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public static void write(Lock lock, int v) {
        try {
            lock.lock();
            Thread.sleep(1000);
            value = v;
            System.out.println("write over!");
            //模拟写操作
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }


    public static void main(String[] args) {
//        Runnable readR = ()-> read(lock);
        Runnable readR = ()-> read(readLock);

//        Runnable writeR = ()->write(lock, new Random().nextInt());
        Runnable writeR = ()->write(writeLock, new Random().nextInt());

        for(int i=0; i<18; i++) new Thread(readR).start();
        for(int i=0; i<2; i++) new Thread(writeR).start();


    }
}

这里的readLock 读锁 是一种乐观锁 就是做读操作时 不排他 可以多线程并发去读
而writeLock 写锁 是一种悲观锁 也是排他锁
读写不同的操作使用不同类型的锁 本质上体现的是应对高并发时读写分离的思想
ReadWriteLock是Java程序中的锁, 但与数据库层面的悲观锁乐观锁思想上有相似之处

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
ReentrantLocksynchronized都是用于实现并发编程中的同步机制,但它们的底层原理和使用方式有所不同。 1. synchronized的底层原理: synchronizedJava中的关键字,它基于进入和退出监视器对象(monitor)来实现方法同步和代码块同步。在Java对象头中,有一个标志位用于表示对象是否被定。当线程进入synchronized代码块时,它会尝试获取对象的,如果已经被其他线程持有,则该线程会被阻塞,直到被释放。当线程退出synchronized代码块时,它会释放对象的,使其他线程可以获取并执行相应的代码。 2. ReentrantLock的底层原理: ReentrantLockJava中的一个类,它使用了一种称为CAS(Compare and Swap)的机制来实现同步。CAS是一种无的同步机制,它利用了CPU的原子指令来实现对共享变量的原子操作。ReentrantLock内部维护了一个同步状态变量,通过CAS操作来获取和释放。当一个线程尝试获取时,如果已经被其他线程持有,则该线程会进入等待状态,直到被释放。与synchronized不同,ReentrantLock提供了更灵活的获取和释放方式,例如可以实现公平和可重入总结: - synchronizedJava中的关键字,基于进入和退出监视器对象来实现同步,而ReentrantLock是一个类,使用CAS机制来实现同步。 - synchronized是隐式,不需要手动获取和释放,而ReentrantLock是显式,需要手动调用lock()方法获取,unlock()方法释放。 - ReentrantLock相比synchronized更灵活,可以实现公平和可重入等特性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值