淺析JAVA Lock鎖原理
同樣是鎖,先說(shuō)說(shuō)synchronized和lock的區(qū)別:
- synchronized是java關(guān)鍵字,是用c++實(shí)現(xiàn)的;而lock是用java類,用java可以實(shí)現(xiàn)
- synchronized可以鎖住代碼塊,對(duì)象和類,但是線程從開(kāi)始獲取鎖之后開(kāi)發(fā)者不能進(jìn)行控制和了解;lock則用起來(lái)非常靈活,提供了許多api可以讓開(kāi)發(fā)者去控制加鎖和釋放鎖等等。
寫個(gè)Demo
static Lock lock = new ReentrantLock();public static void main(String[] args) throws InterruptedException {
lock.lock();//其他沒(méi)拿到鎖的卡住不動(dòng)
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("start to get lock Interruptibly");
lock.unlock(); //看看會(huì)發(fā)生什么,注釋掉再看看
lock.lock();
System.out.println("拿到鎖");
lock.unlock();
System.out.println("釋放鎖");
}
});
thread.start();
Thread.sleep(3000);
lock.unlock();
}
我們自己來(lái)手寫一下lock接口的tryLock()、lock()和unLock()方法,實(shí)現(xiàn)我們自己的myLock。
public class MyLock implements Lock {
//多并發(fā)調(diào)用 0-未占用 大于0-占用
AtomicInteger state = new AtomicInteger();
Thread ownerThread = new Thread();
//等待鎖的隊(duì)列
LinkedBlockingQueue<Thread> waiters = new LinkedBlockingQueue();
@Override
public void lock() {
if (!tryLock()) { //先搶鎖,所以是非公平鎖
//沒(méi)拿到鎖,放到隊(duì)列中去進(jìn)行排隊(duì)
waiters.add(Thread.currentThread());
//等待被喚醒
for (; ; ) {
if (tryLock()) { //非公平鎖情況下,喚醒過(guò)來(lái)繼續(xù)獲取鎖
waiters.poll(); //獲取鎖成功把自己從隊(duì)列中取出來(lái)
return;
} else //獲取鎖失敗
LockSupport.park(); //線程阻塞
}
}
}
@Override
public boolean tryLock() {
if (state.get() == 0) { //如果鎖沒(méi)被占用
if (state.compareAndSet(0, 1)) { //如果成功拿到鎖
ownerThread = Thread.currentThread(); //占用鎖線程改為當(dāng)前線程
return true;
}
}
return false;
}
@Override
public void unlock() {
if (ownerThread != Thread.currentThread()) //占用鎖線程不是當(dāng)前線程無(wú)法釋放鎖
throw new RuntimeException("非法調(diào)用,當(dāng)前鎖不屬于你");
if (state.decrementAndGet() == 0) //如果成功釋放鎖
ownerThread = null; //占用鎖線程置空
//通知其他線程
// Thread thread = null;
//
// while ((thread = waiters.peek()) != null)
// LockSupport.unpark(thread);
Thread thread = waiters.peek(); //獲取隊(duì)列頭部線程,線程還留在隊(duì)列中
if (thread != null) {
LockSupport.unpark(thread); //取消阻塞
}
}
@Override
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
return false;
}
@Override
public Condition newCondition() {
return null;
}
@Override
public void lockInterruptibly() throws InterruptedException {
}
}
幾個(gè)注意點(diǎn):
- 鎖的占用狀態(tài)state是AtomicInteger類型,底層原理是CAS,這是為了保證在多并發(fā)情況下線程安全問(wèn)題;
- 當(dāng)線程1釋放鎖成功時(shí),獲取隊(duì)列頭部線程但并不取出,因?yàn)榉枪芥i模式下,隊(duì)列頭部線程不一定能獲取到鎖;
- LockSupport的park()和unPark()方法是native方法,可以阻塞,喚醒線程;
Lock默認(rèn)是非公平鎖,上面實(shí)現(xiàn)的也是非公平鎖,小伙伴們可以試一試。
公平鎖和非公平鎖區(qū)別:
先等待先獲取鎖是公平鎖;先等待也不一定先獲取鎖,可能被突然到來(lái)的線程獲取到是非公平鎖;
公平鎖的實(shí)現(xiàn):
@Override
public void lock() {
checkQueue();//線程來(lái)的時(shí)候先不獲取鎖,而是先檢查隊(duì)列中有沒(méi)有等待的線程,如果有,直接放入隊(duì)列,如果沒(méi)有,再去獲取鎖
if (!tryLock()) { //先搶鎖,所以是非公平鎖
//沒(méi)拿到鎖,放到隊(duì)列中去進(jìn)行排隊(duì)
waiters.add(Thread.currentThread());
//等待被喚醒
for (; ; ) {
if (tryLock()) { //非公平鎖情況下,喚醒過(guò)來(lái)繼續(xù)獲取鎖
waiters.poll(); //獲取鎖成功把自己從隊(duì)列中取出來(lái)
return;
} else //獲取鎖失敗
LockSupport.park(); //線程阻塞
}
}
}
看完的小伙伴可以去看JDK提供的Lock源碼啦。。
以上就是淺析JAVA Lock鎖原理的詳細(xì)內(nèi)容,更多關(guān)于JAVA Lock鎖原理的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
- java并發(fā)編程專題(四)----淺談(JUC)Lock鎖
- Java Lock鎖多線程中實(shí)現(xiàn)流水線任務(wù)
- Java lock同步鎖使用實(shí)例解析
- Java多線程 ReentrantLock互斥鎖詳解
- Javas使用Redlock實(shí)現(xiàn)分布式鎖過(guò)程解析
- java同步之如何寫一個(gè)鎖Lock
- 詳解java并發(fā)之重入鎖-ReentrantLock
- Java鎖機(jī)制Lock用法示例
- 深入理解java內(nèi)置鎖(synchronized)和顯式鎖(ReentrantLock)
- java基于jedisLock—redis分布式鎖實(shí)現(xiàn)示例代碼
- 詳解Java多線程編程中互斥鎖ReentrantLock類的用法
- Java多線程編程之讀寫鎖ReadWriteLock用法實(shí)例
相關(guān)文章
詳解Mybatis中的 ${} 和 #{}區(qū)別與用法
這篇文章主要介紹了Mybatis中的 ${} 和 #{}區(qū)別與用法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-07-07
Java實(shí)現(xiàn)動(dòng)態(tài)代理
本文給大家介紹的是java使用動(dòng)態(tài)代理類實(shí)現(xiàn)動(dòng)態(tài)代理的方法和示例,這里推薦給大家,有需要的小伙伴參考下吧2015-02-02
java8新特性之stream流中reduce()求和知識(shí)總結(jié)
今天帶大家回顧Java8的新特性,文中對(duì)stream流中reduce()求和的相關(guān)知識(shí)作了詳細(xì)的介紹,對(duì)正在學(xué)習(xí)java的小伙伴們有很好地幫助,需要的朋友可以參考下2021-05-05
解決mapstruct在eclipse生成不了mapper的實(shí)現(xiàn)類問(wèn)題
這篇文章主要介紹了解決mapstruct在eclipse生成不了mapper的實(shí)現(xiàn)類問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-11-11
java使用Filter實(shí)現(xiàn)自動(dòng)登錄的方法
這篇文章主要為大家詳細(xì)介紹了java使用Filter實(shí)現(xiàn)自動(dòng)登錄的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-04-04
springboot如何連接兩個(gè)數(shù)據(jù)庫(kù)(多個(gè))
這篇文章主要介紹了springboot如何連接兩個(gè)數(shù)據(jù)庫(kù)(多個(gè)),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-01-01
springboot中報(bào)錯(cuò)Invalid character found in
這篇文章主要介紹了springboot中報(bào)錯(cuò)Invalid character found in the request的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-09-09
MyBatis學(xué)習(xí)教程(六)-調(diào)用存儲(chǔ)過(guò)程
這篇文章主要介紹了MyBatis學(xué)習(xí)教程(六)-調(diào)用存儲(chǔ)過(guò)程的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,感興趣的朋友一起看下吧2016-05-05
Netty搭建WebSocket服務(wù)器實(shí)戰(zhàn)教程
這篇文章主要介紹了Netty搭建WebSocket服務(wù)器實(shí)戰(zhàn),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2024-03-03

