淺析JAVA Lock鎖原理
同樣是鎖,先說說synchronized和lock的區(qū)別:
- synchronized是java關(guān)鍵字,是用c++實(shí)現(xiàn)的;而lock是用java類,用java可以實(shí)現(xiàn)
- synchronized可以鎖住代碼塊,對(duì)象和類,但是線程從開始獲取鎖之后開發(fā)者不能進(jìn)行控制和了解;lock則用起來非常靈活,提供了許多api可以讓開發(fā)者去控制加鎖和釋放鎖等等。
寫個(gè)Demo
static Lock lock = new ReentrantLock();public static void main(String[] args) throws InterruptedException {
lock.lock();//其他沒拿到鎖的卡住不動(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();
}
我們自己來手寫一下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()) { //先搶鎖,所以是非公平鎖
//沒拿到鎖,放到隊(duì)列中去進(jìn)行排隊(duì)
waiters.add(Thread.currentThread());
//等待被喚醒
for (; ; ) {
if (tryLock()) { //非公平鎖情況下,喚醒過來繼續(xù)獲取鎖
waiters.poll(); //獲取鎖成功把自己從隊(duì)列中取出來
return;
} else //獲取鎖失敗
LockSupport.park(); //線程阻塞
}
}
}
@Override
public boolean tryLock() {
if (state.get() == 0) { //如果鎖沒被占用
if (state.compareAndSet(0, 1)) { //如果成功拿到鎖
ownerThread = Thread.currentThread(); //占用鎖線程改為當(dāng)前線程
return true;
}
}
return false;
}
@Override
public void unlock() {
if (ownerThread != Thread.currentThread()) //占用鎖線程不是當(dāng)前線程無法釋放鎖
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ā)情況下線程安全問題;
- 當(dāng)線程1釋放鎖成功時(shí),獲取隊(duì)列頭部線程但并不取出,因?yàn)榉枪芥i模式下,隊(duì)列頭部線程不一定能獲取到鎖;
- LockSupport的park()和unPark()方法是native方法,可以阻塞,喚醒線程;
Lock默認(rèn)是非公平鎖,上面實(shí)現(xiàn)的也是非公平鎖,小伙伴們可以試一試。
公平鎖和非公平鎖區(qū)別:
先等待先獲取鎖是公平鎖;先等待也不一定先獲取鎖,可能被突然到來的線程獲取到是非公平鎖;
公平鎖的實(shí)現(xiàn):
@Override
public void lock() {
checkQueue();//線程來的時(shí)候先不獲取鎖,而是先檢查隊(duì)列中有沒有等待的線程,如果有,直接放入隊(duì)列,如果沒有,再去獲取鎖
if (!tryLock()) { //先搶鎖,所以是非公平鎖
//沒拿到鎖,放到隊(duì)列中去進(jìn)行排隊(duì)
waiters.add(Thread.currentThread());
//等待被喚醒
for (; ; ) {
if (tryLock()) { //非公平鎖情況下,喚醒過來繼續(xù)獲取鎖
waiters.poll(); //獲取鎖成功把自己從隊(duì)列中取出來
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)分布式鎖過程解析
- 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)文章
Springboot項(xiàng)目參數(shù)校驗(yàn)方式(Validator)
本文介紹了如何在Spring Boot項(xiàng)目中使用`spring-boot-starter-validation`包和注解來實(shí)現(xiàn)請(qǐng)求參數(shù)校驗(yàn),主要介紹了校驗(yàn)注解的使用方法、校驗(yàn)失敗的異常捕獲以及`@Validated`的分組功能2025-02-02
Spring Boot整合Elasticsearch實(shí)現(xiàn)全文搜索引擎案例解析
ElasticSearch作為基于Lucene的搜索服務(wù)器,既可以作為一個(gè)獨(dú)立的服務(wù)部署,也可以簽入Web應(yīng)用中。SpringBoot作為Spring家族的全新框架,使得使用SpringBoot開發(fā)Spring應(yīng)用變得非常簡(jiǎn)單,在本案例中我們給大家介紹Spring Boot整合Elasticsearch實(shí)現(xiàn)全文搜索引擎2017-11-11
java 實(shí)現(xiàn)黃金分割數(shù)的示例詳解
這篇文章主要介紹了java 實(shí)現(xiàn)黃金分割數(shù)的示例詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2021-02-02
MyBatis類型轉(zhuǎn)換模塊的實(shí)現(xiàn)
MyBatis是一個(gè)持久層框架ORM框架,實(shí)現(xiàn)數(shù)據(jù)庫中數(shù)據(jù)和Java對(duì)象中的屬性的雙向映射,那么不可避免的就會(huì)碰到類型轉(zhuǎn)換的問題,本文主要介紹了MyBatis類型轉(zhuǎn)換模塊的實(shí)現(xiàn),感興趣的可以了解一下2023-09-09
mybatis如何使用注解實(shí)現(xiàn)一對(duì)多關(guān)聯(lián)查詢
這篇文章主要介紹了mybatis如何使用注解實(shí)現(xiàn)一對(duì)多關(guān)聯(lián)查詢的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-07-07
Springboot實(shí)例講解實(shí)現(xiàn)專業(yè)材料認(rèn)證管理系統(tǒng)流程
這是一個(gè)基于java的畢業(yè)設(shè)計(jì)項(xiàng)目,畢設(shè)課題為springboot框架的知識(shí)產(chǎn)權(quán)服務(wù)平臺(tái)系統(tǒng),是一個(gè)采用b/s結(jié)構(gòu)的javaweb項(xiàng)目,需要的朋友可以參考下2022-06-06
redis redisson 限流器的實(shí)例(RRateLimiter)
這篇文章主要介紹了redis redisson 限流器的實(shí)例(RRateLimiter),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-07-07

