2013-11-01 78 views
3

假設有以下代碼:Java方法同步使用不當?

class MyClass { 
    synchronized void myMethod1() { 
     //code 
    } 

    synchronized void myMethod2() { 
     //code 
    } 
} 

現在假設myMethod1()myMethod2()訪問不同的數據;現在如果有兩個線程,線程A只調用myMethod1()而線程B只調用myMethod2()

如果線程A正在執行myMethod1(),線程B將等待myMethod2()塊,即使它們不訪問相同的數據並且沒有理由這樣做?據我所知,同步方法使用this對象的監視器作爲實例方法,而MyClass.class對象的監視器用於靜態函數。

回答

1

你在所有的假設中都是正確的。在沒有數據共同的情況下,沒有理由在方法級同步。

3

你對這種情況的理解是正確的。

典型的解決方案是針對有問題的資源分別專用lock objects

class MyClass { 
    private final Lock lock1 = new ReentrantLock(); 
    private final Lock lock2 = new ReentrantLock(); 

    void myMethod1() {   
     lock1.lock(); 

     try { 
     //code 
     } finally { 
     lock1.unlock(); 
     }    
    } 

    void myMethod2() { 
     lock2.lock(); 

     try { 
     //code 
     } finally { 
     lock2.unlock(); 
     }  
    } 
} 
0

是的,聲明這兩種方法爲​​將使他們相互阻塞,即使他們訪問不同的數據元素。

爲了避免這種情況,您可以使用更細密的鎖。例如:

class MyClass { 
    private static final Object lock1 = new Object(); 
    private static final Object lock2 = new Object(); 

    void myMethod1() { 
     synchronized (lock1) { 
      //code 
     } 
    } 

    void myMethod2() { 
     synchronized (lock2) { 
      //code 
     } 
} 
+0

或者一個[鎖定對象(http://docs.oracle.com/javase/tutorial/essential/concurrency/newlocks.html )。 –

+0

@DuncanJones的確如此。 – Mureinik

1

sychronized方法將鎖定對象本身。所以每個方法都必須等待另一個方法完成訪問來釋放對象。如果你的方法是真正訪問不同的數據,你可以這樣做:

class MyClass { 
    private static Object mLock1 = new Object(); 
    private static Object mLock2 = new Object(); 

    void myMethod1() { 
     synchronized(mLock1) { 
      //code 
     } 
    } 

    void myMethod2() { 
     synchronized(mLock2) { 
      //code 
     } 
    } 
} 

然後你就可以獨立訪問它們。

編輯:你基本上可以認爲synchronized方法等價於這個:

void myMethod1() { 
    synchronized(this) { 
     //your code 
    } 
} 

這個樣子是很清楚爲什麼兩個同步的方式阻止對方,因爲他們要等上this鎖免費。

+0

@DuncanJones哦,我想我們在對方的約10秒內發佈。編輯:不知道你暗示「可疑」 –

+0

@DuncanJones啊,np。 :) –

0

可以使用不同的監視和myMethod1myMethod2如下:

class MyClass { 
    Object monitor1 = new Object(); 
    Object monitor2 = new Object(); 
    void myMethod1() { 
     synchornized(monitor1) { 
     //code 
     } 
    } 

    void myMethod2() { 
     synchronized(monitor2) { 
     //code 
     } 
    } 
}