锁原理

    科技2024-07-29  66

    java锁原理

    原子操作:原子操作可以是一个步骤,也可以是多个步骤,但是它执行的顺序不可以被打乱,也不可以被分割,只执行其中一部分操作,将整个操作视为一个整体.,资源在该操作中保持一致.

    CAS(compare and swap)

    CAS(Compare-And-Swap) 算法是硬件对于并发的支持,针对多处理器操作而设计的处理器中的一种特殊指令,用于管理对共享数据的并发访问,比较与交换,首先会对内存中对数据进行比较,相同才进行赋值.内存中进行了限制,同一时间只允许一个线程进行访问内存地址,如果CAS操作失败了则会再次读取值进行比对.直到符合条件.

    cas一路跟踪代码是c语言写的,cmpxchg方法->汇编语言->lock if mp指令(在多个处理器的情况下加lock) ->lock cmpxchg是cpu的汇编指令

    如果在比较过后写回数据就被其他线程打断呢?这种情况也可能出现.所以比较和交换必须要是原子性操作,但是cmpxchg这条指令不是原子的,于是在cmpxchg指令前面加了lock指令.表示在执行cmpxchg操作前锁定这块内存区域,其他线程不能打断.最终还是加锁

    是cpu级别的支持,不能被打断,进行cas时不会进行另一个操作

    旧值,预期值

    总线锁保证原子性:所谓总线锁就是使用处理器提供的一个LOCK#信号,当一个处理器在总线上输出此信号时,其他处理器的请求将被阻塞住,那么该处理器可以独占使用共享内存。

    如i++操作,在java内存中解析成了操作指令

    获取内存中i的值将i+1写回内存

    当有多条线程执行同一段代码时,可能会出现同时读取i的值,造成第二条线程i值无效

    CAS利用了处理器的lock CMPXCHG指令,该指令操作的内存区域就会加锁,导致其他处理器不能同时访问它,保证原子性。

    CAS存在ABA问题

    线程a操作内存中的数字1,将它变成了2,然后又-1写回,这时值还是1线程b比较内存中的值为1,与原来相同,于是cas操作成功

    出现的问题是,虽然值是相同,但是数字1已经不是原来的数字1了,虽然长的一样,但是已经经历过变化了,利用版本号

    分段锁

    假如1000条线程同时对某个数字进行++操作,使用longAdder类加,比使用cas与syn效率高得多,因为它内部使用了分段锁的机制:(cas操作)

    将1000条线程分成4块,每块对某个数进行++,最后再将4个数字加起来

    锁分类

    悲观锁 即必定会发生并发冲突修改,每次线程获取共享资源时,会组织别的线程访问 乐观锁 一般不会发生并发冲突,只有最后更新共享资源时会判断期间有无别的线程修改共享资源,如果发生过则重试.cas就是一种乐观锁的实现方式

    Unsafe工具

    操作内存,进行CAS操作.

    Atomicinteger类内部也采用了unsafe对象的CAS操作

    java.util.concurent包下的类都是原子类

    AtomicintegerAtomicboolean

    原理都是使用cas操作写的.

    CAS在jdk中的使用

    原子操作类并发控制类maplistset线程池

    锁机制

    做并发控制,多线程抢锁(修改锁标记).存在原子性问题.

    锁实现思路:

    T1、t2、t3三个线程抢锁(修改状态),但是由于采用普通方式判断值并且修改会有线程安全问题,会判断无效值,所以采用CAS操作.

    当一个线程通过CAS操作成功抢到锁时,其他没抢到锁的线程就会进入等待队列中.等待第一个t1线程执行完毕并且将锁释放,t2就会接着获取锁.

    情景:

    3条线程分别执行同一个方法中的i++;同时调用了james中的lock方法.

    t1线程第一个获取了锁,并++,t2线程尝试获取锁失败,加入了等待队列中,t3线程也尝试获取锁失败,加入了等待队列,需要有一个无限循环一直尝试唤醒等待队列中的线程去获取锁,

    等待队列的作用是知道当前应该轮到哪一个线程去执行,如果不是当前线程该执行则挂起

    Processed: 0.009, SQL: 8