免费视频淫片aa毛片_日韩高清在线亚洲专区vr_日韩大片免费观看视频播放_亚洲欧美国产精品完整版

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費(fèi)電子書(shū)等14項(xiàng)超值服

開(kāi)通VIP
深入理解synchronized

面試官: 請(qǐng)談?wù)勀銓?duì)synchronized的理解。

小白: 這是一個(gè)java的關(guān)鍵字,用來(lái)控制并發(fā)的,被它鎖住的代碼同一時(shí)刻只能有一個(gè)線(xiàn)程訪(fǎng)問(wèn)。

面試官: 還有嗎?

小白: 沒(méi)有了……

面試官: 那你先回去等通知吧!


synchronized,相信學(xué)過(guò)java的都知道它,但是面試一被問(wèn)到這個(gè),又總是答不出多少東西來(lái)。下面我就將synchronized的知識(shí)點(diǎn)列舉出來(lái),深入理解(要深入它,才能征服它)。


1. 用來(lái)干嘛的?

這是一個(gè)同步關(guān)鍵字,保證同一時(shí)刻只能有一個(gè)線(xiàn)程執(zhí)行被其修飾的方法或代碼塊,可以保證線(xiàn)程安全。

2. 怎么用呢?

這是一個(gè)關(guān)鍵字,可以用來(lái)修飾靜態(tài)方法、實(shí)例方法、代碼塊。注意這里的代碼塊不是類(lèi)中的靜態(tài)代碼塊和構(gòu)造代碼塊,而是方法中的代碼塊。

  • 修飾靜態(tài)方法:介紹它修飾靜態(tài)方法之前,先來(lái)回憶一下靜態(tài)方法的特點(diǎn)。靜態(tài)是該類(lèi)所有實(shí)例共享的,JVM加載該類(lèi)時(shí)就會(huì)對(duì)其進(jìn)行初始化,因?yàn)椴粚儆谌魏我粋€(gè)實(shí)例,所以靜態(tài)方法里面不能用this關(guān)鍵字。如果synchronized修飾靜態(tài)方法,那么鎖對(duì)象是啥呢?首先排除this,因?yàn)檎{(diào)用靜態(tài)方法的時(shí)候可能該類(lèi)都還沒(méi)有實(shí)例。所以修飾靜態(tài)方法的時(shí)候,鎖對(duì)象其實(shí)是當(dāng)前class。
// 靜態(tài)方法
public synchronized static void staticFun(){
    System.out.println("synchronized修飾靜態(tài)方法,鎖對(duì)象是當(dāng)前class");
    // 業(yè)務(wù)代碼……
}
  • 修飾實(shí)例方法:既然都說(shuō)了是實(shí)例方法,那么鎖對(duì)象就是當(dāng)前類(lèi)的實(shí)例。
// 實(shí)例方法
public synchronized void instanceFun(){
    System.out.println("synchronized修飾實(shí)例方法,鎖對(duì)象是類(lèi)實(shí)例");
    // 業(yè)務(wù)代碼……
}
  • 修飾代碼塊:修飾代碼塊,鎖對(duì)象可以是class,也可以是給定的對(duì)象。如果是class,那就是不管該類(lèi)new幾個(gè)實(shí)例,都是屬于這個(gè)類(lèi)的,都會(huì)被鎖住;如果是對(duì)象,那么不同對(duì)象去訪(fǎng)問(wèn)時(shí)是可以獲取到鎖的,所以class作為鎖其實(shí)粒度更粗。
public void fun(){
    synchronized (TestSync.class){ // 鎖對(duì)象是當(dāng)前class
//    synchronized (this){ // 鎖對(duì)象是實(shí)例
        System.out.println("synchronized修飾代碼塊,鎖對(duì)象可以是實(shí)例,可以是類(lèi)");
    }
}

3. 線(xiàn)程A調(diào)用類(lèi)的同步實(shí)例方法,線(xiàn)程B可以同時(shí)調(diào)用類(lèi)的同步靜態(tài)方法嗎?為什么?

我們先用代碼看結(jié)果,再解釋為什么。

 // 靜態(tài)方法
 public synchronized static void staticFun(){
     System.out.println("synchronized修飾靜態(tài)方法,鎖對(duì)象是當(dāng)前class");
     System.out.println(Thread.currentThread().getName() + "進(jìn)入同步靜態(tài)方法");
     System.out.println(Thread.currentThread().getName() + "執(zhí)行結(jié)束");
 }

 // 實(shí)例方法
 public synchronized void instanceFun(){
     System.out.println("synchronized修飾實(shí)例方法,鎖對(duì)象是類(lèi)實(shí)例");
     System.out.println(Thread.currentThread().getName() + "進(jìn)入同步實(shí)例方法");
     try { TimeUnit.SECONDS.sleep(5); } catch (InterruptedException e) { e.printStackTrace(); }
     System.out.println(Thread.currentThread().getName() + "執(zhí)行結(jié)束");
 }

 public static void main(String[] args){
     TestSync testSync = new TestSync();
     new Thread(() -> {
         testSync.instanceFun();
     }, "線(xiàn)程A").start();

     new Thread(() -> {
         staticFun();
     }, "線(xiàn)程B").start();

     new Thread(() -> {
         testSync.instanceFun();
     }, "線(xiàn)程C").start();
 }

運(yùn)行結(jié)果:

運(yùn)行結(jié)果

上面的代碼,線(xiàn)程A調(diào)用實(shí)例方法,并且進(jìn)入方法后線(xiàn)程睡了5秒鐘;線(xiàn)程B調(diào)用靜態(tài)方法,還沒(méi)等線(xiàn)程A結(jié)束,線(xiàn)程B已經(jīng)執(zhí)行結(jié)束了,線(xiàn)程B不需要等線(xiàn)程A釋放鎖也可以執(zhí)行。而線(xiàn)程C,因?yàn)槭峭粋€(gè)對(duì)象去調(diào)用的同步實(shí)例方法,所以得等線(xiàn)程A釋放了鎖,線(xiàn)程C才能拿到執(zhí)行權(quán)。假如線(xiàn)程C是另外再new一個(gè)對(duì)象去調(diào)用的,那么也不需要等待線(xiàn)程A釋放鎖。

從結(jié)果可以得出答案:線(xiàn)程A調(diào)用類(lèi)的同步實(shí)例方法,線(xiàn)程B可以同時(shí)調(diào)用類(lèi)的同步靜態(tài)方法。原因就是同步實(shí)例方法的鎖是對(duì)象鎖,而同步靜態(tài)方法的鎖是類(lèi)鎖,鎖對(duì)象不同,所以可以同時(shí)調(diào)用

4. 可以用String字符串來(lái)做鎖對(duì)象嗎?

可以,但沒(méi)必要。代碼塊的鎖對(duì)象其實(shí)可以是任意對(duì)象,不過(guò)一般都用class或者this,并不建議用string做鎖對(duì)象,因?yàn)橛胹tring很容易造成死鎖。為什么容易造成死鎖呢?因?yàn)镴VM中有個(gè)常量池,比如你定義兩個(gè)字符串:

String str1 = "haha";
String str2 = "haha";

這里明明是兩個(gè)字符串,但其實(shí)是同一個(gè)對(duì)象,因?yàn)檫@樣賦值的String,首先會(huì)看常量池中有沒(méi)有,沒(méi)有就往常量池中添加一個(gè),并指向它,有的話(huà),就直接指向。所以str1和str2都是指向常量池中同一個(gè)對(duì)象。

5. synchronized可以修飾構(gòu)造方法嗎?為什么?

不能修飾構(gòu)造方法,構(gòu)造方法只能有權(quán)限修飾符,比如public、private之類(lèi)的,它本身就是線(xiàn)程安全的。

6. jdk1.6開(kāi)始對(duì)synchronized做了哪些優(yōu)化?

jdk1.6之前,synchronized是很重的鎖,jdk1.6開(kāi)始,做了大量的優(yōu)化,比如用偏向鎖、輕量級(jí)鎖、自旋鎖、適應(yīng)性自旋鎖、鎖消除、鎖粗化等技術(shù)來(lái)減少鎖操作的開(kāi)銷(xiāo)。

7. 你知道synchronized的底層原理嗎?

  • 同步代碼塊:方法里面的同步代碼塊,synchronized底層是通過(guò)監(jiān)視器monitor來(lái)實(shí)現(xiàn)的。通過(guò)指令
javap -c -s -v -l Xxx.class

可以發(fā)現(xiàn)monitorenter指令指向同步代碼塊開(kāi)始的位置,同時(shí)會(huì)嘗試獲取鎖,鎖的計(jì)數(shù)器為0表示可以獲取鎖,獲取后計(jì)數(shù)器變?yōu)?;monitorexit指令指向同步代碼塊結(jié)束的位置,同時(shí)釋放鎖,將鎖的計(jì)數(shù)器置為0。所以獲取鎖就是獲取Monitor的執(zhí)行權(quán)。Monitor是基于C++,由ObjectMonitor實(shí)現(xiàn)的,每個(gè)對(duì)象都內(nèi)置了ObjectMonitor。另外,wait/notify方法也是基于monitor來(lái)實(shí)現(xiàn)的。

  • 同步方法:執(zhí)行上述的javap指令查看同步方法,可以發(fā)現(xiàn)并沒(méi)有monitorenter和monitorexit指令,但是在方法開(kāi)頭有個(gè)名為ACC_SYNCHRONIZED的flag標(biāo)識(shí),同步方法就是通過(guò)這個(gè)標(biāo)識(shí)來(lái)控制同步操作的。

8. synchronized和ReentrantLock有何異同?

相同點(diǎn):

  • 兩者都是可重入鎖;

  • 都可實(shí)現(xiàn)選擇性通知;

不同點(diǎn):

  • synchronized是JVM層面的,ReentrantLock是API層面的;

  • synchronized是非公平鎖,ReentrantLock可以指定為公平鎖或者非公平鎖;

  • synchronized無(wú)需手動(dòng)釋放鎖,ReentrantLock需要手動(dòng)釋放鎖;

  • synchronized等待不能中斷,ReentrantLock等待可通過(guò)lock.lockInterruptibly()中斷等待;


掃描二維碼

本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶(hù)發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
面試常考:Synchronized 有幾種用法?
線(xiàn)程八鎖
是同步方法還是 synchronized 代碼?– 詳解多線(xiàn)程同步規(guī)則
Java中Synchronized的用法
深入理解Java并發(fā)之synchronized實(shí)現(xiàn)原理
解析Java線(xiàn)程編程中的線(xiàn)程安全與synchronized的使用
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長(zhǎng)圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服