不就是鎖嗎怎么還這么細(xì)分,好吧得查資料看看
synchronized關(guān)鍵字的用法主要有以下幾種:
1.作用在非靜態(tài)方法上
非靜態(tài)方法是只能提供類的實(shí)例進(jìn)行調(diào)用,所以實(shí)際上就是對調(diào)用方法的對象加鎖,俗稱對象鎖
2.作用在靜態(tài)方法上
靜態(tài)方法是可以通過類名直接調(diào)用,所以實(shí)際上就是對調(diào)用方法的類加鎖,俗稱類鎖
3.作用在代碼塊
根據(jù)傳入的是類對象或類實(shí)例判斷加鎖方式
場景分析
public class SyncStaticClazz {
public static synchronized void method1(){
System.out.println("static ----method1----"+Thread.currentThread());
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static synchronized void method2(){
System.out.println("static ----method2----"+Thread.currentThread());
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public synchronized void method3(){
System.out.println("unstatic ----method3----"+Thread.currentThread());
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class SyncClazz {
public synchronized void method1(){
System.out.println("normal----method1----"+Thread.currentThread());
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
System.out.println(e.getMessage());
e.printStackTrace();
}
}
public synchronized void method2()
System.out.println("normal----method2----" + Thread.currentThread());
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void method3() {
synchronized (SyncClazz.class) {
System.out.println("normal----method3----" + Thread.currentThread());
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void method4() {
synchronized (SyncClazz.this) {
System.out.println("normal----method4----" + Thread.currentThread());
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void method5() {
synchronized (SyncClazz.class) {
System.out.println("normal----method5----" + Thread.currentThread());
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
場景1
new Thread(new Runnable() {
@Override
public void run() {
SyncStaticClazz.method1();
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
SyncStaticClazz.method2();
}
}).start();
結(jié)果:互斥
解析:靜態(tài)同步方法的加鎖范圍是整個(gè)類,所以無論是使用對象或類去訪問靜態(tài)同步方法,鎖都會(huì)加到類對象上。就好比是房子的大門,房子內(nèi)不論有多少房間,只要有一個(gè)人打開大門進(jìn)入到房子里,其他人就只能等他出來之后再進(jìn)去,而已經(jīng)進(jìn)去的人擁有所有房間的使用權(quán)。
場景2
描述:在不同線程中用不同的類實(shí)例訪問相同靜態(tài)方法
new Thread(new Runnable() {
@Override
public void run() {
SyncStaticClazz syncStaticClazz = new SyncStaticClazz();
syncStaticClazz.method1();
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
SyncStaticClazz syncStaticClazz = new SyncStaticClazz();
syncStaticClazz.method1();
}
}).start();
結(jié)果:互斥
解析:和場景1相同,靜態(tài)方法雖然可以被類實(shí)例訪問,但鎖依然是類鎖
場景3
描述:同一個(gè)對象在不同線程中訪問不同的非靜態(tài)同步方法
SyncClazz syncClazz = new SyncClazz();
new Thread(new Runnable() {
@Override
public void run() {
syncClazz.method1();
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
syncClazz.method2();
}
}).start();
結(jié)果:互斥
解析:非靜態(tài)方法上加的是對象鎖,當(dāng)對象調(diào)用一個(gè)非靜態(tài)的同步方法時(shí),其他的非靜態(tài)同步方法需要等待被執(zhí)行。
場景4
描述:不同對象在不同線程中訪問同一個(gè)非靜態(tài)方法
new Thread(new Runnable() {
@Override
public void run() {
SyncClazz syncClazz = new SyncClazz();
syncClazz.method1();
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
SyncClazz syncClazz = new SyncClazz();
syncClazz.method1();
}
}).start();
結(jié)果:不互斥
解析:因?yàn)橥ㄟ^不同的對象調(diào)用的是非靜態(tài)方法,雖然調(diào)用的是同一個(gè)方法,但是非靜態(tài)方法加的鎖是對象鎖,針對的是對象并不是方法,所以可以并發(fā)執(zhí)行,不會(huì)互斥。如果像場景1中的比喻的話,就是兩個(gè)對象是兩套房子,戶型相同而已。
場景5
描述:不同對象在不同線程中訪問同一個(gè)非靜態(tài)非同步方法,方法內(nèi)通過synchronized鎖定代碼塊,且鎖定對象為類對象
new Thread(new Runnable() {
@Override
public void run() {
SyncClazz syncClazz = new SyncClazz();
syncClazz.method3();
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
SyncClazz syncClazz = new SyncClazz();
syncClazz.method3();
}
}).start();
結(jié)果:互斥
解析:因?yàn)榉椒╩ethod3()內(nèi)的synchronized鎖的是SyncClazz.class,也就是鎖定的是類對象,所以與場景2相同
場景6
描述:同一個(gè)對象在不同線程中訪問不同的非靜態(tài)非同步方法,方法內(nèi)通過synchronized鎖定代碼塊,且鎖定對象為類對象
SyncClazz syncClazz = new SyncClazz();
new Thread(new Runnable() {
@Override
public void run() {
syncClazz.method3();
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
syncClazz.method5();
}
}).start();
}
結(jié)果:互斥
解析:因?yàn)榉椒╩ethod3()和method5()內(nèi)的synchronized鎖的是SyncClazz.class,也就是鎖定的是類對象,所以與場景2相同
場景7
描述:同一個(gè)對象在不同線程中訪問不同方法,一個(gè)調(diào)用靜態(tài)方法,一個(gè)調(diào)用非靜態(tài)方法
SyncStaticClazz syncClazz = new SyncStaticClazz();
new Thread(new Runnable() {
@Override
public void run() {
syncClazz.method1();
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
syncClazz.method3();
}
}).start();
結(jié)果:不互斥
解析:雖然是同一個(gè)對象調(diào)用,但是兩個(gè)方法的鎖類型不同,靜態(tài)方法是類鎖,非靜態(tài)方法是對象鎖,所以不會(huì)互斥
場景8
描述:同一個(gè)對象在不同線程中訪問不同synchronized代碼塊方法,一個(gè)調(diào)用類對象同步,一個(gè)調(diào)用類實(shí)例同步
SyncClazz syncClazz = new SyncClazz();
new Thread(new Runnable() {
@Override
public void run() {
syncClazz.method3();
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
syncClazz.method4();
}
}).start();
結(jié)果:不互斥
解析:與場景7相同
總結(jié)
對象鎖僅鎖當(dāng)前對象,不同對象之間不會(huì)互斥
靜態(tài)方法上的鎖是類鎖,非靜態(tài)方法上的鎖是對象鎖
所有靜態(tài)同步方法互斥,無論是通過類調(diào)用還是對象調(diào)用
靜態(tài)方法上加synchronized與在非靜態(tài)方法內(nèi)加synchronized(Xxx.class)效果一致,都是類鎖