转载于三太子敖丙!!!
synchronized实现原理
contentionList(请求锁线程队列) entryList(有资格的候选者队列) waitSet(wait方法后阻塞队列) onDeck(竞争候选者) ower(竞争到锁线程) !ower(执行成功释放锁后状态);Synchronized 是非公平锁。
Synchronized 在线程进入 ContentionList 时,等待的线程会先尝试自旋获取锁,如果获取不到就进入 ContentionList,这明显对于已经进入队列的线程是不公平的,还有一个不公平的事情就是自旋获取锁的线程还可能直接抢占 OnDeck 线程的锁资源。
底层是由一对monitorenter和monitorexit指令实现的(监视器锁)
每个对象有一个监视器锁(monitor)。当monitor被占用时就会处于锁定状态,线程执行monitorenter指令时尝试获取monitor的所有权,过程:
-
如果monitor的进入数为0,则该线程进入monitor,然后将进入数设置为1,该线程即为monitor的所有者。
-
如果线程已经占有该monitor,只是重新进入,则进入monitor的进入数加1.
-
如果其他线程已经占用了monitor,则该线程进入阻塞状态,直到monitor的进入数为0,再重新尝试获取monitor的所有权。
ReentrantLock 是如何实现可重入性的 ?
内部自定义了同步器 Sync,加锁的时候通过CAS 算法 ,将线程对象放到一个双向链表 中,每次获取锁的时候 ,看下当前维 护的那个线程ID和当前请求的线程ID是否一样,一样就可重入了;
ReentrantLock如何避免死锁?
-
响应中断lockInterruptibly()
-
可轮询锁tryLock()
-
定时锁tryLock(long time)
tryLock 和 lock 和 lockInterruptibly 的区别
(1):tryLock 能获得锁就返回 true,不能就立即返回 false,
(2):tryLock(long timeout,TimeUnit unit),可以增加时间限制,如果超过该时间段还没获得锁,返回 false
(3):lock 能获得锁就返回 true,不能的话一直等待获得锁
(4):lock 和 lockInterruptibly,如果两个线程分别执行这两个方法,但此时中断这两个线程, lock 不会抛出异常,而 lockInterruptibly 会抛出异常。
CountDownLatch和CyclicBarrier的区别是什么
CountDownLatch是等待其他线程执行到某一个点的时候,在继续执行逻辑(子线程不会被阻塞,会继续执行),只能被使用一次。最常见的就是join形式,主线程等待子线程执行完任务,在用主线程去获取结果的方式(当然不一定),内部是用计数器相减实现的(没错,又特么是AQS),AQS的state承担了计数器的作用,初始化的时候,使用CAS赋值,主线程调用await()则被加入共享线程等待队列里面,子线程调用countDown的时候,使用自旋的方式,减1,知道为0,就触发唤醒。
CyclicBarrier回环屏障,主要是等待一组线程到底同一个状态的时候,放闸。CyclicBarrier还可以传递一个Runnable对象,可以到放闸的时候,执行这个任务。CyclicBarrier是可循环的,当调用await的时候如果count变成0了则会重置状态,如何重置呢,CyclicBarrier新增了一个字段parties,用来保存初始值,当count变为0的时候,就重新赋值。还有一个不同点,CyclicBarrier不是基于AQS的,而是基于RentrantLock实现的。存放的等待队列是用了条件变量的方式。
synchronized与ReentrantLock区别
-
都是可重入锁;R是显示获取和释放锁,s是隐式;
-
R更灵活可以知道有没有成功获取锁,可以定义读写锁,是api级别,s是JVM级别;
-
R可以定义公平锁;Lock是接口,s是java中的关键字
什么是信号量Semaphore
信号量是一种固定资源的限制的一种并发工具包,基于AQS实现的,在构造的时候会设置一个值,代表着资源数量。信号量主要是应用于是用于多个共享资源的互斥使用,和用于并发线程数的控制(druid的数据库连接数,就是用这个实现的),信号量也分公平和非公平的情况,基本方式和reentrantLock差不多,在请求资源调用task时,会用自旋的方式减1,如果成功,则获取成功了,如果失败,导致资源数变为了0,就会加入队列里面去等待。调用release的时候会加一,补充资源,并唤醒等待队列。
Semaphore 应用
-
acquire() release() 可用于对象池,资源池的构建,比如静态全局对象池,数据库连接池;
-
可创建计数为1的S,作为互斥锁(二元信号量)
可重入锁概念
(1):可重入锁是指同一个线程可以多次获取同一把锁,不会因为之前已经获取过还没释放而阻塞;
(2):reentrantLock和synchronized都是可重入锁
(3):可重入锁的一个优点是可一定程度避免死锁