1. 程式人生 > >區分同步代碼塊、靜態同步方法、非靜態同步方法的鎖

區分同步代碼塊、靜態同步方法、非靜態同步方法的鎖

同步 zed 方法 extends his 類名 ole true 解決

同步代碼塊、靜態同步方法、非靜態同步方法的鎖分別是:

  • 同步代碼塊可以使用自定義的Object對象,也可以使用this或者當前類的字節碼文件(類名.class);
  • 靜態同步方法的鎖是當前類的字節碼文件(類名.class);
  • 非靜態同步方法的鎖是this;

證明方法:

  • 兩個線程之間實現同步,一個線程使用同步代碼塊,一個線程使用同步方法。
  • 如果這兩個線程同步了,說明了使用的是同一個鎖;
創建線程類(以售票為例)
/**
 * @methodDesc 售票線程類
 */
public class ThreadTrain extends Thread {
    // 總共又100張
    private static int trainCount = 100;    
    protected static boolean flag = true;

    @Override
    public void run() {     
        while (trainCount > 0) {
            if (flag) { // 執行同步代碼塊,this鎖
                System.out.println("flag==="+flag);
                // 出售火車票
                sale1();        
            }else {
                System.out.println("flag==="+flag);
                // 出售火車票
                sale11();
            }
            flag = !flag;
        }
    }
    
    // 同步代碼塊
    public void sale1() {
        // 同步代碼塊,包裹需要解決線程安全問題的代碼塊,兩個線程同時訪問
        synchronized (this) { // 只能有一個線程進行訪問,必須拿到鎖的時候才能訪問
            if (trainCount > 0) { // 不加判斷,會出現出售第101張票的情況
                System.out.println(Thread.currentThread().getName() + ", 出售第" + (100 - trainCount + 1) + "張票");
                trainCount--;
            }
        }
    }
    
    // 靜態同步代碼塊
    public void sale2() {
        // 同步代碼塊,包裹需要解決線程安全問題的代碼塊,兩個線程同時訪問
        synchronized (ThreadTrain.class) { // 只能有一個線程進行訪問,必須拿到鎖的時候才能訪問
            if (trainCount > 0) { // 不加判斷,會出現出售第101張票的情況
                System.out.println(Thread.currentThread().getName() + ", 出售第" + (100 - trainCount + 1) + "張票");
                trainCount--;
            }
        }
    }

    // 同步方法
    public synchronized void sale11() {     
        if (trainCount > 0) { // 不加判斷,會出現出售第101張票的情況
            System.out.println(Thread.currentThread().getName() + ", 出售第" + (100 - trainCount + 1) + "張票");
            trainCount--;
        }
    }
    
    // 靜態同步方法
    public static synchronized void sale22() {      
        if (trainCount > 0) { // 不加判斷,會出現出售第101張票的情況
            System.out.println(Thread.currentThread().getName() + ", 出售第" + (100 - trainCount + 1) + "張票");
            trainCount--;
        }
    }
}
創建測試類
/**
 * @methodDesc 多線程模擬售票問題
 */
public class ThreadDemo {
    public static void main(String[] args) throws InterruptedException {
        // 創建售票線程對象
        ThreadTrain train1 = new ThreadTrain();
        // 創建多個售票窗口,並給其取別名
        Thread t1 = new Thread(train1, "窗口1");
        Thread t2 = new Thread(train1, "窗口2");
        t1.start(); 
        t2.start();
    }
}
驗證方法
  • 驗證非靜態同步方法,修改run方法為
        public void run() {     
        while (trainCount > 0) {
            if (flag) { // 執行同步代碼塊,this鎖
                System.out.println("flag==="+flag);
                // 出售火車票
                sale1();        
            }else {
                System.out.println("flag==="+flag);
                // 出售火車票
                sale11();
            }
            flag = !flag;
        }
    }
  • 驗證靜態同步方法,修改run方法為
        public void run() {     
        while (trainCount > 0) {
            if (flag) { // 執行同步代碼塊,this鎖
                System.out.println("flag==="+flag);
                // 出售火車票
                sale2();        
            }else {
                System.out.println("flag==="+flag);
                // 出售火車票
                sale22();
            }
            flag = !flag;
        }
    }

區分同步代碼塊、靜態同步方法、非靜態同步方法的鎖