java Synchronized一些列問題解答

對於synchronized這個關鍵字,相信大家都不陌生。 可能對於一些在剛出學校的同學,在面試的時候卡在這裏而讓你在接下來的交鋒中敗下陣來,今天就帶你弄懂這個關鍵字咯~~。

問題)當一個線程進入一個對象的一個synchronized方法後,其它線程是否可進入此對象的其它方法。

網上對於這個問題的回答,有很多是錯誤的。你百度的結果可能是這個錯誤的答案 —->不能,一個對象的synchronized方法只能由一個線程訪問。而就我面試的一些公司的情況絕大多數公司就是看網上那些錯誤的答案。 其實正確答案要分類討論的。

1、當一個線程進入到一個(非static 沒有wait() ) synchronized方法後,其他線程是否可以訪問其他非靜態普通方法?

         可以
package com.icoder.model;

public class SynchronizedTest {

    public void normalMetod(String msg){
        System.out.println(msg);
    }
    public synchronized void normalSyncMetod(String msg){
        System.out.println(msg);
        try {
            Thread.sleep(10*1000);
        } catch (Exception e) {
        }
    }
    public static void main(String[] args) {
        SynchronizedTest st=new SynchronizedTest();
        Thread1 t1=st.new Thread1(st);
        Thread2 t2=st.new Thread2(st);

        t1.start();
        t2.start();
    }
    class Thread1 extends Thread{
        SynchronizedTest t;
        public Thread1 (SynchronizedTest t){
            this.t=t;
        }
        @Override
        public void run() {
            normalSyncMetod("normal sync method");
        }
    }
    class Thread2 extends Thread{
        SynchronizedTest t;
        public Thread2 (SynchronizedTest t){
            this.t=t;
        }
        @Override
        public void run() {
            normalMetod("normal method");
        }
    }
}

normal sync method
normal method

2、當一個線程進入到一個synchronized方法後,其他線程是否可以訪問其他的非靜態synchronized方法?

    不能
package com.icoder.model;

public class SynchronizedTest {


    public synchronized void normalSyncMetod(String msg){
        System.out.println(msg);
        try {
            Thread.sleep(10*1000);
        } catch (Exception e) {
        }
    }
    public synchronized void normalSyncMetod2(String msg){
        System.out.println(msg);
        try {
            Thread.sleep(10*1000);
        } catch (Exception e) {
        }
    }
    public static void main(String[] args) {
        SynchronizedTest st=new SynchronizedTest();
        Thread1 t1=st.new Thread1(st);
        Thread2 t2=st.new Thread2(st);

        t1.start();
        t2.start();
    }
    class Thread1 extends Thread{
        SynchronizedTest t;
        public Thread1 (SynchronizedTest t){
            this.t=t;
        }
        @Override
        public void run() {
            normalSyncMetod("normal sync method");
        }
    }
    class Thread2 extends Thread{
        SynchronizedTest t;
        public Thread2 (SynchronizedTest t){
            this.t=t;
        }
        @Override
        public void run() {
            normalSyncMetod2("normal sync method2");
        }
    }
}
3、當一個進程進入一個帶(waite)synchronized方法後,其他進程是否可以進入其他的synchronized方法

    可以
package com.icoder.model;

public class SynchronizedTest {


    public synchronized void normalSyncMetod(String msg){
        System.out.println(msg);
        try {
            wait();
            Thread.sleep(10*1000);
        } catch (Exception e) {
        }
    }
    public synchronized void normalSyncMetod2(String msg){
        System.out.println(msg);
        try {
            Thread.sleep(10*1000);
            notifyAll();//你可以在其他線程中喚醒處於waite的線程
        } catch (Exception e) {
        }
    }
    public static void main(String[] args) {
        SynchronizedTest st=new SynchronizedTest();
        Thread1 t1=st.new Thread1(st);
        Thread2 t2=st.new Thread2(st);

        t1.start();
        t2.start();
    }
    class Thread1 extends Thread{
        SynchronizedTest t;
        public Thread1 (SynchronizedTest t){
            this.t=t;
        }
        @Override
        public void run() {
            normalSyncMetod("normal sync method");
        }
    }
    class Thread2 extends Thread{
        SynchronizedTest t;
        public Thread2 (SynchronizedTest t){
            this.t=t;
        }
        @Override
        public void run() {
            normalSyncMetod2("normal sync method2");
        }
    }
}
4、當一個線程進入一個synchronized方法後,其他線程是否可以進入一個static synchronized方法?

    可以
package com.icoder.model;

public class SynchronizedTest {


    public  synchronized void normalSyncMetod(String msg){
        System.out.println(msg);
        try {
            Thread.sleep(10*1000);
        } catch (Exception e) {
        }
    }
    public static  synchronized void staticSyncMetod2(String msg){
        System.out.println(msg);
        try {
            Thread.sleep(10*1000);
        } catch (Exception e) {
        }
    }
    public static void main(String[] args) {
        SynchronizedTest st=new SynchronizedTest();
        Thread1 t1=st.new Thread1(st);
        Thread2 t2=st.new Thread2(st);

        t1.start();
        t2.start();
    }
    class Thread1 extends Thread{
        SynchronizedTest t;
        public Thread1 (SynchronizedTest t){
            this.t=t;
        }
        @Override
        public void run() {
            normalSyncMetod("normal sync method");
        }
    }
    class Thread2 extends Thread{
        SynchronizedTest t;
        public Thread2 (SynchronizedTest t){
            this.t=t;
        }
        @Override
        public void run() {
            staticSyncMetod2("static sync method2");
        }
    }
}
5、當一個線程進入靜態synchronized方法後,是否可以進入一個另外一個靜態synchronized方法?
        不能
package com.icoder.model;

public class SynchronizedTest {


    public static  synchronized void normalSyncMetod(String msg){
        System.out.println(msg);
        try {
            Thread.sleep(10*1000);
        } catch (Exception e) {
        }
    }
    public static  synchronized void staticSyncMetod2(String msg){
        System.out.println(msg);
        try {
            Thread.sleep(10*1000);
        } catch (Exception e) {
        }
    }
    public static void main(String[] args) {
        SynchronizedTest st=new SynchronizedTest();
        Thread1 t1=st.new Thread1(st);
        Thread2 t2=st.new Thread2(st);

        t2.start();
        t1.start();
    }
    class Thread1 extends Thread{
        SynchronizedTest t;
        public Thread1 (SynchronizedTest t){
            this.t=t;
        }
        @Override
        public void run() {
            normalSyncMetod("normal sync method");
        }
    }
    class Thread2 extends Thread{
        SynchronizedTest t;
        public Thread2 (SynchronizedTest t){
            this.t=t;
        }
        @Override
        public void run() {
            staticSyncMetod2("static sync method2");
        }
    }
}
6、一個線程進入靜態synchronized方法後,其他線程是否可以進入普通的靜態方法?
        可以
package com.icoder.model;

public class SynchronizedTest {


    public static   void staticMetod(String msg){
        System.out.println(msg);
        try {
            Thread.sleep(10*1000);
        } catch (Exception e) {
        }
    }
    public static  synchronized void staticSyncMetod2(String msg){
        System.out.println(msg);
        try {
            Thread.sleep(10*1000);
        } catch (Exception e) {
        }
    }
    public static void main(String[] args) {
        SynchronizedTest st=new SynchronizedTest();
        Thread1 t1=st.new Thread1(st);
        Thread2 t2=st.new Thread2(st);

        t2.start();
        t1.start();
    }
    class Thread1 extends Thread{
        SynchronizedTest t;
        public Thread1 (SynchronizedTest t){
            this.t=t;
        }
        @Override
        public void run() {
            staticMetod("static method");
        }
    }
    class Thread2 extends Thread{
        SynchronizedTest t;
        public Thread2 (SynchronizedTest t){
            this.t=t;
        }
        @Override
        public void run() {
            staticSyncMetod2("static sync method2");
        }
    }
}

----OVER!

到這裏,動手敲了代碼的同學都明白了吧?

我來總結下:


1、synchronized是對該類的當前實例對象的 synchronized代碼區 加鎖。所有被 synchronized修飾的方法全部在這個代碼區裏面,有個監視器,只能由然後當前對象的一個線程進入。
2、static synchronized是對該類進行加鎖,換句話就是對所有實例對象的公共synchroinzed代碼區加鎖。所有的static synchronized修飾的方法都在這個代碼區,有個監視器,只能讓一個線程進入。
3、一旦在方法中有waite()釋放資源鎖,那麼則可以進入。

synchronized與static synchronized 的區別
synchronized是對類的當前實例進行加鎖,防止其他線程同時訪問該類的該實例的所有synchronized塊,注意這裏是“類的當前實例”, 類的兩個不同實例就沒有這種約束了。那麼static synchronized恰好就是要控制類的所有實例的訪問了,static synchronized是限制線程同時訪問jvm中該類的所有實例同時訪問對應的代碼快。實際上,在類中某方法或某代碼塊中有 synchronized,那麼在生成一個該類實例後,改類也就有一個監視快,放置線程併發訪問改實例synchronized保護快,而static synchronized則是所有該類的實例公用一個監視快了,也也就是兩個的區別了,也就是synchronized相當於 this.synchronized,而static synchronized相當於Something.synchronized.

出個題目吧,還是蠻有代表性的

pulbic class Something(){ 

 public synchronized void isSyncA(){} 
 public synchronized void isSyncB(){} 
 public static synchronized void cSyncA(){} 
 public static synchronized void cSyncB(){} 

} 

那麼,加入有Something類的兩個實例a與b,那麼下列組方法何以被1個以上線程同時訪問呢
a. x.isSyncA()與x.isSyncB()  
b. x.isSyncA()與y.isSyncA() 
c. x.cSyncA()與y.cSyncB() 
d. x.isSyncA()與Something.cSyncA() 

a 不行, b 可以,c不行, d可以

所以答案是b d

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章