什么是cassychronized?
- cas的定义:在操作系统中,cas通常代表“Compare And Swap它是一种解决并发访问问题的原子操作。具体来说,CAS操作将比较和交换内存位置的值。只有当内存位置的值等于预期值时,新值才会写入该位置。如果内存位置的值与预期值不相等,则表明内存位置已被其他线程修改,CAS操作不会进行任何修改,并返回失败状态。
- cas所涉及的指令:cpmxchg,他通常和自旋锁在一起(spin lock)这个自旋锁在os//c++实现略有不同,具体如下:看os
- spininux内核下的linux lock
typedef struct spinlock { union { atomic_t count; };} spinlock_t;
- c++中spin lock
#include <atomic> // class头文件 SpinLock {public: SpinLock() { flag.clear(std::memory_order_release); } void lock() { while (flag.test_and_set(std::memory_order_acquire)) ; // 忙等待 } void unlock() { flag.clear(std::memory_order_release); }private: std::atomic_flag flag;};
在多线程序中,CAS可以用来保证数据的一致性和正确性,防止竞争条件等问题。因此,CAS操作是许多并发编程框架和实现中常用的技术之一。
什么是公平锁,什么是公平锁,先说reentrantlock。- 结论:公平和非公平锁的区别在于抢锁前是否排队。一旦你进入团队,你将永远排队
- 公平锁紧逻辑:线程进入-调用lock方法-tryacquire 获取当前线程,判断锁的状态是否为0,锁是否被持有——如果没有人持有,看看是否排队,如果有人排队;如果锁被持有,锁失败,自己进入队,如果你是手持,选择再次尝试锁)
- 非公平锁抢锁逻辑:线程进入-调用lock方法-然后tryacquire(这里的具体行为如下:获取当前线程-获取锁状态是否为0-”,判断是否被持有。如果被持有,就会自旋等待。如果你成功了,你就会得到锁。如果你失败了,进入队列。这个时候,你会看一个节点是不是head。如果你选择一次试图拿到锁,
- 这是别人画的图片,讲述整个过程
- 队列:刚才说到入队,队列的数据结构如下
public class Node{volatile Node prev;volatile Node next;volatile Thread thread;}
关于synchronized是否公平锁定
1. 正如上面所说,是否公平取决于入队前是否抢锁,入队后总是排队
锁的基本知识首先,介绍锁和内存分布
- 无锁:分为101 无锁可以偏向或偏向锁。如果前52个字符不是0,则表示偏向锁。前52位是偏向线程id。如果后3位是001,则表示无锁。以下是相应的情况
- 轻量锁 00,一个64位,前62位是指针,看后两位
- 重新加锁和重新加锁的区别
- 偏向于锁膨胀的具体过程,结合c++代码
- 偏向锁的获取过程中,首先有一个锁对象lock,在当前线程下创建lockrecord,然后判断锁是否自己持有,是否过期,然后拿到锁。这就是偏向锁。第一次获得,比如第二次获得,还是会建立lockrecord,判断自己是否持有过期。如果满意,不需要cas就能拿到锁,所以性能最好。释放的过程是从栈中找到相应的lockrecord释放
- 轻量级锁:假设T1释放了偏向锁,T2进来拿锁,此时需要先撤销偏向(简单来说,撤销偏向被放置为无锁001),其内存变化如下:(见c++文件重写)
- 这时,如果t2释放锁,t3来了,t3先生成无锁markword 然后displacedword在lockrocrd中 设置为markword,然后cas判断当前对象头和内存中对应的markword是否相等。如果相等,将对象头中的markword修改为指向lockrecord的指针,同时,将对象头中markword的后两位改为00;
4. 轻量锁膨胀为重量锁:T3修改前,T4进来完成T3要完成的操作,T3加锁失败后会膨胀,涉及到 pthredmutex;
- 批量偏差涉及连续偏差取消20次和40次的两个阈值:结论:当取消偏差超过锁阈值时 20 次后,jvm 会这样想,我是不是偏向错了,因此,在锁定这些对象时,它会再次偏向t2;当偏向锁被取消40次时,认为对象设计有问题;然后JVM将取消对应对象类别的所有对象;新的实例对象也不可偏向
- 锁膨胀流程图:
大概逻辑如上图,这里的文字版;
获得锁的对象lockeee->创建lockrecord->让lockrecordobj关联lockee->获取lockee的头信息-此时判断是否偏向锁(这里有一些细节,比如初始化01,看了一遍也记不住)
1.是偏向锁,获取当前线程ID,看看是否偏向自己,如果偏向自己,看看是否关闭偏向锁,如果关闭偏向锁升级为轻锁;如果不关闭,看看是否过期或偏向他人,创建偏向自己的马克,设置对象头,成功获得锁,升级为轻锁;
2.不偏向锁升级为轻量锁
不爱世间浮华,不写红尘纷扰