密码锁 java接口_从synchronized和lock区别入手聊聊java锁机制
寫這篇文章之前,我去百度了一下啥叫鎖,百度百科上寫道:置于可啟閉的器物上,以鑰匙或暗碼開啟。確實(shí)我們一般理解的鎖就是門鎖,密碼鎖,但是在計(jì)算機(jī)科學(xué)中,鎖又是啥,說實(shí)話,這個(gè)問題我也思考了很久,也沒法很好的用一兩句話就讓人聽得明白,也不想有人看到我的文章,然后將我的結(jié)論當(dāng)作答案,我覺得最好的答案還是在探索的過程中得到的,接下來我們就好好探索一番。
作為一名java程序員,最開始接觸到的鎖就是synchronized,書本上是這么寫的,老師也是這么說的,至于為啥叫鎖,可能也沒多少人真的去思考過。不知道有沒有同學(xué)和我一樣,經(jīng)歷過只知道用synchronized,后來逐漸的了解ReentrantLock,讀寫鎖,然后又了解了aqs,后來通過百度google,看一些博客(這個(gè)我要吐槽一下,在學(xué)習(xí)過程中遇到過很多文章寫的有問題的,反而誤導(dǎo)了我),后面看了看synchronized的源碼,最后對(duì)比synchronized和ReentrantLock才加深了對(duì)鎖的一些認(rèn)知(說實(shí)話,作為一個(gè)剛畢業(yè)3年的非科班出身碼農(nóng),我也不敢保證自己寫的就一定對(duì),算是學(xué)習(xí)過程中的一些感悟吧),那接下來我就按照學(xué)習(xí)順序來逐漸展開。
先來一段簡(jiǎn)單的synchronized使用代碼:
public static voidmain(String[] args) {
String s= newString();synchronized(s) {
TestJni jni= newTestJni();
jni.jniHello();
}
}
上面代碼做的事情很簡(jiǎn)單,如下圖所示,有A B C D E多個(gè)線程同時(shí)來到synchronized包含的代碼塊,A先一步進(jìn)來了,那么BCDE都得等,等我A執(zhí)行完他們才能進(jìn)來執(zhí)行。
? ? ? ?
synchronized用起來確實(shí)很簡(jiǎn)單,我們也可以放在方法上,但是其本質(zhì)還是鎖的對(duì)象,這個(gè)我們后面分析源碼一看就知道了。
隨著開發(fā)時(shí)間越長(zhǎng),synchronized在有些復(fù)雜場(chǎng)景下(如需要可中斷,可控制時(shí)間搶鎖,需要多個(gè)等待隊(duì)列分別控制,讀寫鎖等場(chǎng)景的時(shí)候)無法滿足我們的需求,那么就要用到Lock,下面我們先介紹一下Lock的簡(jiǎn)單使用:
Lock lock = newReentrantLock();
lock.lock();try{
System.out.println("線程:"+Thread.currentThread().getName()+ " 進(jìn)來啦");
}finally{
lock.unlock();
}
上面是一種最簡(jiǎn)單的使用,和synchronized作用是一樣的,不過加鎖之后必須要解鎖,且必須緊跟try - finally塊解鎖,使用起來稍微復(fù)雜一點(diǎn),容易出錯(cuò)。
我們?cè)俳榻B一種可中斷的使用方式:
public static voidmain(String[] args) {
Thread thread= new Thread(() ->{try{
lock.lockInterruptibly();try{
testLock();
}finally{
lock.unlock();
}
}catch(Exception e){
}
});
thread.start();
thread.interrupt();
}public static voidtestLock(){
condition.signalAll();
System.out.println("線程:"+Thread.currentThread().getName()+ " 進(jìn)來啦");
}
這種方式呢,在拿鎖被park住了,如果剛好這時(shí)候被打斷了,就會(huì)響應(yīng)打斷退出搶鎖并拋出異常,至于捕獲到異常開發(fā)者怎么做,那就得根據(jù)業(yè)務(wù)來分別處理了。
而像可控制時(shí)間的其實(shí)就要稍微復(fù)雜一點(diǎn),先看一下synchronized中的使用:
static TestHash s = newTestHash();public static voidmain(String[] args) {
Thread thread1= new Thread(()->{
testLock();
});
Thread thread2= new Thread(()->{synchronized(s) {try{
TimeUnit.SECONDS.sleep(1);
}catch(InterruptedException e) {
}
s.notify();
testLock();
}
});
thread1.start();
thread2.start();
}public static voidtestLock(){synchronized(s) {
System.out.println("線程:"+Thread.currentThread().getName()+ " 進(jìn)來啦");try{
s.wait();
System.out.println("線程:"+Thread.currentThread().getName()+ " 叫醒啦");
}catch(InterruptedException e) {
System.out.println("拋異常啦");
}
}
}
這個(gè)例子看著要比前面幾個(gè)復(fù)雜一點(diǎn),首先thread1會(huì)進(jìn)入testLock方法,并拿到鎖,thread2等了1秒叫醒thread1(這里就是簡(jiǎn)單的wait/notify的使用),然后在拿到鎖的情況下,再次進(jìn)入testLock方法并拿到鎖,由于沒人喚醒了,會(huì)一直卡在這里(這里證明了synchronized的可重入),結(jié)果我就不貼了,感興趣的可以拿著代碼去試。
而ReentrantLock的使用也差不多,就是提前用lock去new一個(gè)Condition:
static ReentrantLock lock = newReentrantLock();static Condition condition =lock.newCondition();public static voidmain(String[] args) {
Thread thread1= new Thread(()->{
testWaitSingal();
},"thread1");
Thread thread2= new Thread(()->{
lock.lock();try{
TimeUnit.SECONDS.sleep(1);
condition.signal();
testWaitSingal();
}catch(InterruptedException e) {
}finally{
lock.unlock();
}
},"thread2");
thread1.start();
thread2.start();
}public static voidtestWaitSingal(){
lock.lock();try{
System.out.println("線程:"+Thread.currentThread().getName()+ " 進(jìn)來啦");
condition.await();
System.out.println("線程:"+Thread.currentThread().getName()+ " 叫醒啦");
}catch(InterruptedException e) {
System.out.println("拋異常啦");
}finally{
lock.unlock();
}
}
可以看到兩種用法基本上是一致的,也就是將synchronized換成了lock,wait換成await,notify換成singal,
總結(jié):
基本上我們平時(shí)用到的synchronized關(guān)鍵字的用法也就這些,但lock鎖不一樣,它還支持如上述的中斷,更復(fù)雜的讀寫鎖,還可以在aqs的基礎(chǔ)上衍生出更多,如countDownLatch,cyclicBarrier等,可以支持我們做更多,但是不是lock就可以完全替代synchronized了呢,其實(shí)synchronized也有自己的優(yōu)點(diǎn),簡(jiǎn)單,不易出錯(cuò),性能也不比lock差(有的書上寫道synchronized性能比lock好,但其實(shí)就算好也不會(huì)好太多,對(duì)于我們來說,基本上可以忽略),真要說選哪個(gè),我的建議是優(yōu)先選synchronized,如果有特殊業(yè)務(wù)特殊需求synchronized無法滿足,那當(dāng)然是要用lock,不過,一定要記得釋放鎖哦。
本來打算結(jié)合reentrant和synchronized直接串起來講的,但是確實(shí)有點(diǎn)多,這一篇就當(dāng)作是后面的引子吧。
總結(jié)
以上是生活随笔為你收集整理的密码锁 java接口_从synchronized和lock区别入手聊聊java锁机制的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 杨梅有虫能不能吃?专家科普:就是蛋白质
- 下一篇: spring boot 入门_玩转spr