1. 程式人生 > 其它 >整理synchronized、static synchronized以及synchronized(obj)區別

整理synchronized、static synchronized以及synchronized(obj)區別

技術標籤:java

文章目錄


對java中synchronized應用場景做下整理,方面自己以後檢視

synchronized使用者髮結論:

  • 1.public synchronized void syncMethod(String flag){} 鎖當前物件this,等價程式碼塊鎖synchronized (this){}
    • 1.1 同一個例項物件同一個時刻只能有一個在呼叫,不同例項可以同時呼叫
  • 2.public static synchronized void syncStaticMethod{}是鎖當前對應class物件,等價程式碼塊鎖synchronized (SyncServiceTest.class){}
    ,其中SyncServiceTest為當前類
    • 2.1 鎖物件為SyncServiceTest.class與呼叫方法的物件無關,因此同一個時刻不管是否為同一個物件呼叫都只有一個在執行
  • 3.synchronized (obj){},鎖obj物件
  • 4.注意上面三種鎖的物件都是不同的,分別對應當前物件this、當前類物件SyncServiceTest.class以及obj物件 因此相互之間呼叫不會有影響
  • 5.synchronized方法、程式碼塊相互之間是否有影響關鍵是看鎖的是否為同一個物件

demo測試用例

public class SyncServiceTest {

    private Object lockObj = new Object();

    public void syncLockObj(String flag) {
        synchronized (lockObj) {
            print(flag);
        }
    }

    public synchronized void syncMethod(String flag) {
        //等價synchronized (this){}
        print(flag);
    }

    public void syncCodeBlockByThis(String flag) {
        synchronized (this) {
            print(flag);
        }
    }
    public static synchronized void syncStaticMethod(String flag) {
        /**
         *1.static synchronized是鎖對應class,與synchronized (SyncServiceTest.class)寫法等價
         *
         *2. synchronized (obj){},鎖obj物件
         *
         *3. public synchronized void syncMethod(String flag){} 鎖當前物件this,等價synchronized (this){}
         *
         * - 注意上面三種鎖的物件都是不同的,分別對應SyncServiceTest.class,obj,this 因此相互之間呼叫不會有影響
         *
         * - synchronized方法、程式碼塊相互之間是否有影響關鍵是看鎖的是否為同一個物件
         *
         */
        print(flag);
    }

    public void syncCodeBlockByClass(String flag) {
        //需要驗證 對應統一 object  synchronized 修改的程式碼同一個時間點只能有一個在訪問
        synchronized (SyncServiceTest.class) {
            print(flag);
        }
    }

    public static void print(String msg) {
        for (int i = 0; i < 3; i++) {
            //Thread.currentThread().getStackTrace()[2]獲取上一級呼叫的方法
            //Thread.currentThread().getStackTrace()[1]獲取當前方法(即print)
            String log = String.format("method=%s,thread=%s,flag=%s,i=%s", Thread.currentThread().getStackTrace()[2].getMethodName(), Thread.currentThread().getName(), msg, i);
            System.out.println(log);
            randomSleep(500);
        }
    }

    /**
     * @param timer 毫秒
     * @return
     */
    private static void randomSleep(int timer) {

        long sleepTimer = Math.round(Math.random() * timer);
        try {
            Thread.sleep(sleepTimer);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    //--------------------test method分割線---------------

    public void testInvokeTwoSyncObj() {
        System.out.println("測試呼叫synchronized(obj)");
        //結論同一個時刻之後有一個方法獲取到成員變數(lockObj)的鎖
        SyncServiceTest service = new SyncServiceTest();
        Thread t1 = new Thread(() -> {
            service.syncLockObj("lock1");
        });
        Thread t2 = new Thread(() -> {
            service.syncLockObj("lock2");
        });
        t1.start();
        t2.start();
    }

    public void testInvokeSyncObjAndSyncMethod() {
        System.out.println("測試呼叫synchronized(obj)與public synchronized void syncMethod(String flag){}");
        //成員變數(lockObj)的鎖物件與普通方法鎖物件不是同一個,因此不會相互影響
        //普通方法syncMethod()鎖物件為當前物件this,成員變數鎖物件是lockObj本身
        SyncServiceTest service = new SyncServiceTest();
        Thread t1 = new Thread(() -> {
            service.syncLockObj("lock1");
        });
        Thread t2 = new Thread(() -> {
            service.syncMethod("lock2");
        });
        t1.start();
        t2.start();
    }

    public void testInvokeTwoSyncMethod() {
        System.out.println("測試呼叫public synchronized void syncMethod(String flag){}");
        SyncServiceTest service = new SyncServiceTest();
        Thread t1 = new Thread(() -> {
            service.syncMethod("lock1");
        });
        Thread t2 = new Thread(() -> {
            service.syncMethod("lock2");
        });
        t1.start();
        t2.start();
    }

    public void testTwoDemoInvokeSyncMethod() {
        System.out.println("測試呼叫public void syncMethod(){}");
        Thread t1 = new Thread(() -> {
            new SyncServiceTest().syncMethod("lock1");
        });
        Thread t2 = new Thread(() -> {
            new SyncServiceTest().syncMethod("lock2");
        });
        t1.start();
        t2.start();
    }

    public void testSyncStaticMethod() {
        System.out.println("測試呼叫public synchronized void syncMethod(){}");
        Thread t1 = new Thread(() -> {
            new SyncServiceTest().syncStaticMethod("lock1");
        });
        Thread t2 = new Thread(() -> {
            new SyncServiceTest().syncStaticMethod("lock2");
        });
        t1.start();
        t2.start();
    }
    public void testSyncStaticMethodAndLockClass() {
        System.out.println("測試呼叫public static synchronized void syncMethod(){}與synchronized(SyncServiceTest.class)");
        Thread t1 = new Thread(() -> {
            new SyncServiceTest().syncStaticMethod("lock1");
        });
        Thread t2 = new Thread(() -> {
            new SyncServiceTest().syncCodeBlockByClass("lock2");
        });
        t1.start();
        t2.start();
    }


    public static void main(String[] args) {
        SyncServiceTest t = new SyncServiceTest();
//        t.testInvokeTwoSyncObj();
//        t.testInvokeSyncObjAndSyncMethod();
//        t.testInvokeTwoSyncMethod();
//        t.testTwoDemoInvokeSyncMethod();
        t.testSyncStaticMethodAndLockClass();
    }

}