1.悲观锁 :锁住资源其他线程不能在访问
2.乐观锁: 不锁资源,默认其他进程不会修改资源
锁住同步资源失败 线程是否需要阻塞?
阻塞
不阻塞: 自旋锁 适应性自旋锁 减少了线程上下文的其二环 因为是不阻塞 而是一直原地等待
多线程竞争同步资源的流程细节有没有区别
1.不锁住资源 多个线程中只有一个能修改资源,其他线程重试
2.同意下城执行同步资源时自动获取资源 偏向锁
3.多个线程竞争同步资源时,没有获取资源的线程自旋等待锁释放 轻量级锁
4.多个线程竞争同步资源时 没有获取资源的线程线程阻塞等待唤醒 重量级锁
自旋锁和自适应自旋锁
AQS同步器 Abstrac Queue Sych
ReentranLock
公平锁和非公平锁
排队公平
非公平 插队 如果失败再按公平走
非公平吞吐量要大得多
可重入锁 加多次锁
们把使用Lock接口实现线程同步的锁称之为 显示锁,使用synchronized的称为 隐式锁 或 java内置锁
LockSupport 挂起和唤醒线程
void park() 阻塞当前线程
void unpark() 获取 许可证
被阻塞的线程可以通过 interrupt 方法来唤醒
void parkNanos
该方法的不同在于 ,如果
没有拿到许可证,则调用线程会被挂起 nanos 时间后修改为自动返回。
(1)wait和notify都是Object中的方法,在调用这两个方法前必须先获得锁对象,但是park不需要获取某个对象的锁就可以锁住线程。
(2)notify只能随机选择一个线程唤醒,无法唤醒指定的线程,unpark却可以唤醒一个指定的线程。
阻塞
wait notify 让出资源锁 非公平锁 下一个获得的线程 粗颗粒
lockspoout park unpark 不让资源锁 即不可被重用
锁
synchronized
lock unlock 直接锁
condition.await singleall 让出资源 也是使用了
LockSupport 类 park 和 unpark 方法
锁的底层支持 AQS 抽象同步队列
AbstractQueuedSynchronizer
AQS 是一个 FIFO 的双向队列,其内部通过节点 head 和 tail 记录队首和队尾元素 队列元素的类型为 Node 其中 Node 中的 thread 变量用来存放进入 AQS队列里面的线程:
ode 节点内部的 SHARED 用来标记该线程是获取共享资源时被阻塞
挂起后放入 AQS 队列的, EXCLUSIVE 用来标记线程是获取独占资源时被挂起后放入
AQS 队列的 ; waitStatus 记录当前线程等待状态,可以为 CANCELLED (线程被取消了)、
SIGNAL ( 线程需要被唤醒)、 CONDITION (线程在条件队列里面等待〉、 PROPAGATE (释
放共享资源时需要通知其他节点〕; prev 记录当前节点的前驱节点, next 记录当前节点的
后继节点 。
在 AQS 中 维持了 一 个 单 一 的状态信息 state,可以通过 getState 、 setState 、
compareAndS etState 函数修改其值 。 对于 Reentran tLock 的 实 现来说, state 可以用 来表示
当 前线程获取锁的可重入次数 ;对于 读写锁 ReentrantReadWriteLock 来说 , state 的 高 16
位表示读状态,也就是获取该读锁的次数,低 16 位表示获取到写锁的线程的可重入次数;
对于 semaphore 来说, state 用来表示当前可用信号的 个数:对于 CountDownlatch 来说,
state 用 来表示计数器当前的值 。
assert 关键字 表示断言,
ReetrantLock 是一种独占式的可重入锁 就是可以多次 加锁 释放锁 他是通过内部一个status状态量来进行处理的 悲观锁
然后他其实真正实现的是一个sycn的内部类 实现了AQS这个抽象类,那个状态量 其实也是AQS的 state 是一个用volatile 修饰的私有变量
然后实现了AQS里面的一些方法 包括加锁去锁啊 判断是否有锁 等一些方法
还有一个比较特别的就是 他可以设置条件变量锁,就是那个condition 锁 ,然后可以通过await方法和single方法来实现线程的阻塞和唤醒
然后他有公平和非公平两种创建。
公平就是按顺序先来后到 非公平就是可以插队
通过理解实现一个线程安全list 理解 volatile和ReetrantLock 的使用
volatile的共享和RL 的原子性
并发包 源码解读
内存操作 对象内存
Unsafe unsafe = Unsafe.getUnsafe();
unsafe.objectFieldOffset(AtomicInteger.class.getDeclaredField("value"));
使用了大量CAS操作 比较并交换
1.AtomicBoolean
2.AtomicIntger
3.AtomicLong