如何判斷鎖的是什么?
首先我們先來看下面的代碼。思考下面兩個(gè)問題。
/**
* 1.Q:下面程序執(zhí)行后,是先打印 “看電影” 還是 “玩游戲” 呢? A:先打印“看電影”
* 2.Q:若watchMovie方法延遲4秒,是先打印 “看電影” 還是 “玩游戲” 呢? A:先打印“看電影” */
public class Test01 {
public static void main(String[] args){
TV tv = new TV();
new Thread(()->{
tv.watchMovie();
},"A").start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
tv.playGame();
},"B").start();
}
}
class TV{
public synchronized void watchMovie(){
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("看電影");
}
public synchronized void playGame(){
System.out.println("打游戲");
}
}
synchronized 鎖的對(duì)象是方法的調(diào)用者!
就上面代碼而言,看電影和玩游戲兩個(gè)方法是用的TV對(duì)象的一把鎖,所以誰先拿到誰先執(zhí)行!
我們?cè)谒伎枷旅鎯蓚€(gè)問題。
/**
* 3.Q:增加了一個(gè)普通方法后,是先打印 “開機(jī)” 還是 “看電影” 呢? A:先打印“開機(jī)”
* 4.Q:若兩個(gè)對(duì)象,兩個(gè)同步方法,是先打印 “看電影” 還是 “打游戲” 呢? A:先打印“打游戲” */
public class Test02 {
public static void main(String[] args){
TV2 tv1 = new TV2();
TV2 tv2= new TV2();
new Thread(()->{
tv1.watchMovie();
},"A").start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
tv2.playGame();
},"B").start();
}
}
class TV2{
public synchronized void watchMovie(){
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("看電影");
}
public synchronized void playGame(){
System.out.println("打游戲");
}
public void open(){
System.out.println("開機(jī)");
}
}
就問題3而言,我們之前了解過synchronized 鎖的對(duì)象是方法的調(diào)用者!而普通方法沒有synchronized修飾,不受鎖控制,所以先執(zhí)行。
就問題4而言,兩個(gè)對(duì)象,就是兩個(gè)調(diào)用者,也就意味著有兩把鎖,所以要受時(shí)間延遲影響,先打印“打游戲”!
好的,那我們?cè)倏聪旅鎯山M問題:
/**
* 5.Q:增加兩個(gè)靜態(tài)方法,只有一個(gè)對(duì)象,是先打印 “看電影” 還是 “玩游戲” 呢? A:先打印“看電影”
* 6.Q:若兩個(gè)對(duì)象,兩個(gè)靜態(tài)方法,是先打印 “看電影” 還是 “玩游戲” 呢? A:先打印“看電影” */
public class Test03 {
public static void main(String[] args){
TV3 tv1 = new TV3();
TV3 tv2 = new TV3();
new Thread(()->{
tv1.watchMovie();
},"A").start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
tv2.playGame();
},"B").start();
}
}
class TV3{
public static synchronized void watchMovie(){
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("看電影");
}
public static synchronized void playGame(){
System.out.println("打游戲");
}
}
static 靜態(tài),全局唯一,static 方法在類加載的時(shí)候就存在了,synchronized 鎖static 方法本質(zhì)是鎖TV對(duì)象的Class模板,類的Class模板只有一個(gè),換而言之,調(diào)用者只有一個(gè),鎖只有一把,所以還是誰先拿到誰先執(zhí)行!
最后再來看下面兩個(gè)問題:
/**
* 7.Q:增加1個(gè)靜態(tài) synchronized 方法,1個(gè)普通 synchronized 方法,只有一個(gè)對(duì)象,是先打印 “看電影” 還是 “打游戲” 呢? A:先打印“打游戲”
* 8.Q:增加1個(gè)靜態(tài) synchronized 方法,1個(gè)普通 synchronized 方法,兩個(gè)對(duì)象,是先打印 “看電影” 還是 “打游戲” 呢? A:先打印“打游戲” */
public class Test04 {
public static void main(String[] args){
TV4 tv1 = new TV4();
TV4 tv2 = new TV4();
new Thread(()->{
tv1.watchMovie();
},"A").start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
tv2.playGame();
},"B").start();
}
}
class TV4{
public static synchronized void watchMovie(){
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("看電影");
}
public synchronized void playGame(){
System.out.println("打游戲");
}
}
就問題7而言,靜態(tài)synchronized方法和普通synchronized鎖的調(diào)用者不是一個(gè),前者是類的Class模板,后者是對(duì)象,所以有兩個(gè)調(diào)用者,也就存在兩把鎖,因此,時(shí)間延遲的原因占主導(dǎo)。同理問題8也是如此,兩個(gè)調(diào)用者兩把鎖!
總結(jié):關(guān)鍵理解鎖的對(duì)象是方法的調(diào)用者!鎖的對(duì)象無外乎兩種,一種是new的對(duì)象,而一種就是Class模板。要分清具體情況下究竟鎖的是什么?