一個問題,有簡單的類如下,有一個靜態synchronized方法,兩個非靜態synchronized方法,這個類的兩個對象(實例):A,B,那麼以下幾種情況中,那種組合的方法執行會發生互斥(鎖競爭)?
1、SyncTest.method1,A.method1;2、A.method2, B.method2;3、SyncTest.method1,A.method2;4、A.method2,A.method3
類示例代碼如下:
public class SyncTest {
public synchronized static void method1(String name){
System.out.println(name+" is running method1 start");
try{
Thread.sleep(2000);
}catch (InterruptedException e){
}
System.out.println(name+" is running method1 end");
}
public synchronized void method2(String name){
System.out.println(name+" is running method2 start");
try{
Thread.sleep(2000);
}catch (InterruptedException e){
}
System.out.println(name+" is running method2 end");
}
public synchronized void method3(String name){
System.out.println(name+" is running method3 start");
try{
Thread.sleep(2000);
}catch (InterruptedException e){
}
System.out.println(name+" is running method3 end");
}
}
先說結果:
發生互斥情況的組合爲: 1、SyncTest.method1,A.method1;4、A.method2,A.method3
不互斥的情況爲:2、A.method2, B.method2;3、SyncTest.method1,A.method2;
其實也並不複雜,瞭解synchronize的作用域這個問題就很清晰了、
1、synchronized修飾靜態方法時,鎖是類鎖(.class)。這個範圍就比對象鎖大。這裏就算是不同對象,但是隻要是該類的對象,就使用的是同一把鎖。多個線程調用該類的同步的靜態方法時,都會阻塞。所以 1 成立
2、synchronized修飾普通方法時,鎖是對象鎖(this)。
當該類中有多個普通方法被synchronized修飾(同步),那麼這些方法的鎖都是這個類的一個對象this。多個線程訪問這些方法時,如果這些線程調用方法時使用的是同一個該類的對象,雖然他們訪問不同方法,但是他們使用同一個對象來調用,那麼這些方法的鎖就是一樣的,就是這個對象,那麼會造成阻塞。如果多個線程通過不同的對象來調用方法(一般都是通過同一個對象訪問),那麼他們的鎖就是不一樣的,不會造成阻塞。
所以4 是使用一個對象中的兩個synchronized方法,執行時都鎖當前對象,導致出現競爭。
用於驗證的執行代碼示例如下:
package com.java.learn.mine.basic.lock.synchronizetest;
public class SyncTest {
public synchronized static void method1(String name){
System.out.println(name+" is running method1 start");
try{
Thread.sleep(2000);
}catch (InterruptedException e){
}
System.out.println(name+" is running method1 end");
}
public synchronized void method2(String name){
System.out.println(name+" is running method2 start");
try{
Thread.sleep(2000);
}catch (InterruptedException e){
}
System.out.println(name+" is running method2 end");
}
public synchronized void method3(String name){
System.out.println(name+" is running method3 start");
try{
Thread.sleep(2000);
}catch (InterruptedException e){
}
System.out.println(name+" is running method3 end");
}
public static void main(String[] args){
SyncTest syncTest = new SyncTest();
// SyncTest syncTestA2 = new SyncTest();
Thread threadA = new ThreadA(syncTest);
Thread threadB = new ThreadB(syncTest);
threadA.start();
threadB.start();
}
}
class ThreadA extends Thread{
private SyncTest syncTest;
public ThreadA(SyncTest syncTest){
this.syncTest = syncTest;
}
@Override
public void run(){
// SyncTest.method1("ThreadA");
// SyncTest syncTest = new SyncTest();
// syncTest.method2("ThreadA");
// syncTest.method2(ThreadA.class.getName());
SyncTest.method1(ThreadA.class.getName());
}
}
class ThreadB extends Thread{
private SyncTest syncTest;
public ThreadB(SyncTest syncTest){
this.syncTest = syncTest;
}
@Override
public void run(){
// SyncTest syncTest = new SyncTest();
// SyncTest.method1("ThreadB");
// syncTest.method1("ThreadB");
// syncTest.method2(ThreadB.class.getName());
syncTest.method3(ThreadB.class.getName());
}
}
執行後,可以通過打印信息中的start、end來判定兩個線程是否同時開始執行方法;進而確定是否發生了鎖競爭