java程式設計開發多執行緒鎖的8個問題分析
1. 程式程式碼
package com.atguigu.thread;
import java.util.concurrent.TimeUnit;
class Phone
{
public synchronized void sendSMS() throws Exception
{
System.out.println("------sendSMS");
}
public synchronized void sendEmail() throws Exception
{
System.out.println("------sendEmail");
}
public void getHello()
{
System.out.println("------getHello");
}
}
/**
*
* @Description: 8鎖
* @author xialei
*
1 標準訪問,先列印簡訊還是郵件
2 停4秒在簡訊方法內,先列印簡訊還是郵件
3 新增普通的hello方法,是先打簡訊還是hello
4 現在有兩部手機,先列印簡訊還是郵件
5 兩個靜態同步方法,1部手機,先列印簡訊還是郵件
6 兩個靜態同步方法,2部手機,先列印簡訊還是郵件
7 1個靜態同步方法,1個普通同步方法,1部手機,先列印簡訊還是郵件
8 1個靜態同步方法,1個普通同步方法,2部手機,先列印簡訊還是郵件
* ---------------------------------
*
*/
public class Lock_8
{
public static void main(String[] args) throws Exception
{
Phone phone = new Phone();
Phone phone2 = new Phone();
new Thread(() -> {
try {
phone.sendSMS();
} catch (Exception e) {
e.printStackTrace();
}
}, "AA").start();
Thread.sleep(100);
new Thread(() -> {
try {
phone.sendEmail();
//phone.getHello();
//phone2.sendEmail();
} catch (Exception e) {
e.printStackTrace();
}
}, "BB").start();
}
}
複製程式碼
2. 鎖的8個問題
(1) 標準訪問,先列印簡訊還是郵件
(2) 停4秒在簡訊方法內,先列印簡訊還是郵件
(3) 普通的hello方法,是先打簡訊還是hello
(4) 現在有兩部手機,先列印簡訊還是郵件
(5) 兩個靜態同步方法,1部手機,先列印簡訊還是郵件
(6) 兩個靜態同步方法,2部手機,先列印簡訊還是郵件
(7) 1個靜態同步方法,1個普通同步方法,1部手機,先列印簡訊還是郵件
(8) 1個靜態同步方法,1個普通同步方法,2部手機,先列印簡訊還是郵件
3. 鎖的8個問題分析
一個物件裡面如果有多個synchronized方法,某一個時刻內,只要一個執行緒去呼叫其中的一個synchronized方法了,其它的執行緒都只能等待,換句話說,某一個時刻內,只能有唯一一個執行緒去訪問這些synchronized方法。
鎖的是當前物件this,被鎖定後,其它的執行緒都不能進入到當前物件的其它的synchronized方法。
加個普通方法後發現和同步鎖無關。
換成兩個物件後,不是同一把鎖了,情況立刻變化。
synchronized實現同步的基礎:Java中的每一個物件都可以作為鎖。
具體表現為以下3種形式。
對於普通同步方法,鎖是當前例項物件。
對於靜態同步方法,鎖是當前類的Class物件。
對於同步方法塊,鎖是Synchonized括號裡配置的物件
當一個執行緒試圖訪問同步程式碼塊時,它首先必須得到鎖,退出或丟擲異常時必須釋放鎖。
也就是說如果一個例項物件的非靜態同步方法獲取鎖後,該例項物件的其他非靜態同步方法必須等待獲取鎖的方法釋放鎖後才能獲取鎖,可是別的例項物件的非靜態同步方法因為跟該例項物件的非靜態同步方法用的是不同的鎖,所以毋須等待該例項物件已獲取鎖的非靜態同步方法釋放鎖就可以獲取他們自己的鎖。
所有的靜態同步方法用的也是同一把鎖——類物件本身,這兩把鎖是兩個不同的物件,所以靜態同步方法與非靜態同步方法之間是不會有競態條件的。但是一旦一個靜態同步方法獲取鎖後,其他的靜態同步方法都必須等待該方法釋放鎖後才能獲取鎖,而不管是同一個例項物件的靜態同步方法之間,還是不同的例項物件的靜態同步方法之間,只要它們同一個類的例項物件!