synchronized關鍵字的四種加鎖方式

本篇我們來講解synchronized關鍵字的四種加鎖使用方式,並對其進行比較Github項目地址

synchronized對方法加鎖

public class SynchronizedTest {
    static class Thread1 extends Thread {
        Utils mUtils;

        Thread1(Utils utils) {
            mUtils = utils;
        }

        @Override
        public void run() {
            super.run();
            mUtils.method1();
        }
    }

    static class Thread2 extends Thread {
        Utils mUtils;

        Thread2(Utils utils) {
            mUtils = utils;
        }

        @Override
        public void run() {
            super.run();
            mUtils.method2();
        }
    }

    static class Utils {
        synchronized void method1() {
            System.out.println("method1 exec before -- threadName:" + Thread.currentThread().getName());
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("method1 exec after-- threadName:" + Thread.currentThread().getName());
        }

        synchronized void method2() {
            System.out.println("method2 exec before -- threadName:" + Thread.currentThread().getName());
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("method2 exec after-- threadName:" + Thread.currentThread().getName());
        }
    }

    public static void main(String[] args) {
        Utils utils = new Utils();
        Utils utils2 = new Utils();
        Thread thread1 = new Thread1(utils);
        Thread thread2 = new Thread2(utils2);
        thread1.start();
        thread2.start();
    }
}
//執行結果
method1 exec before -- threadName:Thread-0
method2 exec before -- threadName:Thread-1
method1 exec after-- threadName:Thread-0
method2 exec after-- threadName:Thread-1
  • 我們看到如果對方法整體加鎖的話,線程中如果不是同一個Utils對象的話,那麼線程0和線程1其實是並行的,並沒有達到同步的目的。如果我們僅僅修改運行代碼如下,使得傳入的對象爲同一個對象的話,那麼就是同步的效果,如下看到是線程1執行完畢,然後線程2纔開始執行:
public static void main(String[] args) {
        Utils utils = new Utils();
        Thread thread1 = new Thread1(utils);
        Thread thread2 = new Thread2(utils);
        thread1.start();
        thread2.start();
    }
//執行結果
method1 exec before -- threadName:Thread-0
method1 exec after-- threadName:Thread-0
method2 exec before -- threadName:Thread-1
method2 exec after-- threadName:Thread-1

使用synchronized(this)

public class SynchronizedTest2 {
    static class Thread1 extends Thread {
        Utils mUtils;

        Thread1(Utils utils) {
            mUtils = utils;
        }

        @Override
        public void run() {
            super.run();
            mUtils.method1();
        }
    }

    static class Thread2 extends Thread {
        Utils mUtils;

        Thread2(Utils utils) {
            mUtils = utils;
        }

        @Override
        public void run() {
            super.run();
            mUtils.method2();
        }
    }

    static class Utils {
        void method1() {
            synchronized (Utils.this) {
                System.out.println("method1 exec before -- threadName:" + Thread.currentThread().getName());
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("method1 exec after-- threadName:" + Thread.currentThread().getName());
            }
        }

        void method2() {
            synchronized (Utils.this) {
                System.out.println("method2 exec before -- threadName:" + Thread.currentThread().getName());
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("method2 exec after-- threadName:" + Thread.currentThread().getName());
            }
        }
    }

    public static void main(String[] args) {
        Utils utils = new Utils();
        Thread thread1 = new Thread1(utils);
        Thread thread2 = new Thread2(utils);
        thread1.start();
        thread2.start();
    }
}
//執行結果
method1 exec before -- threadName:Thread-0
method1 exec after-- threadName:Thread-0
method2 exec before -- threadName:Thread-1
method2 exec after-- threadName:Thread-1
  • synchronized(this)代碼塊加鎖,傳入同一個對象是同步,如果傳入的不是同一個對象,如下所示,則是異步的(線程0和線程1併發執行)。
public static void main(String[] args) {
        Utils utils = new Utils();
        Utils utils2 = new Utils();
        Thread thread1 = new Thread1(utils);
        Thread thread2 = new Thread2(utils2);
        thread1.start();
        thread2.start();
}
//執行結果
method1 exec before -- threadName:Thread-0
method2 exec before -- threadName:Thread-1
method1 exec after-- threadName:Thread-0
method2 exec after-- threadName:Thread-1

使用synchronized(xxx.class)

public class SynchronizedTest3 {
    static class Thread1 extends Thread {
        Utils mUtils;

        Thread1(Utils utils) {
            mUtils = utils;
        }

        @Override
        public void run() {
            super.run();
            mUtils.method1();
        }
    }

    static class Thread2 extends Thread {
        Utils mUtils;

        Thread2(Utils utils) {
            mUtils = utils;
        }

        @Override
        public void run() {
            super.run();
            mUtils.method2();
        }
    }

    static class Utils {
        void method1() {
            synchronized (Utils.class) {
                System.out.println("method1 exec before -- threadName:" + Thread.currentThread().getName());
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("method1 exec after-- threadName:" + Thread.currentThread().getName());
            }
        }

        void method2() {
            synchronized (Utils.class) {
                System.out.println("method2 exec before -- threadName:" + Thread.currentThread().getName());
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("method2 exec after-- threadName:" + Thread.currentThread().getName());
            }
        }
    }

    public static void main(String[] args) {
        Utils utils = new Utils();
        Thread thread1 = new Thread1(utils);
        Thread thread2 = new Thread2(utils);
        thread1.start();
        thread2.start();
    }
}
//執行結果
method1 exec before -- threadName:Thread-0
method1 exec after-- threadName:Thread-0
method2 exec before -- threadName:Thread-1
method2 exec after-- threadName:Thread-1
  • synchronized(xxx.class)加鎖方式, 不管線程中傳入的是不是同一個對象,都是同步,上面是同一個對象是同步的效果,下面看傳入的不是同一個對象的話,效果也是一樣的同步。
public static void main(String[] args) {
        Utils utils = new Utils();
        Utils utils2 = new Utils();
        Thread thread1 = new Thread1(utils);
        Thread thread2 = new Thread2(utils2);
        thread1.start();
        thread2.start();
}
//執行結果
method1 exec before -- threadName:Thread-0
method1 exec after-- threadName:Thread-0
method2 exec before -- threadName:Thread-1
method2 exec after-- threadName:Thread-1

靜態方法前加synchronized

因爲靜態方法可以直接用類名調用,所以就沒有實例化對象,從測試來看也是同步的效果。

public class SynchronizedTest4 {
    static class Thread1 extends Thread {
        @Override
        public void run() {
            super.run();
            Utils.method1();
        }
    }

    static class Thread2 extends Thread {

        @Override
        public void run() {
            super.run();
            Utils.method2();
        }
    }

    static class Utils {
        synchronized static void method1() {
            System.out.println("method1 exec before -- threadName:" + Thread.currentThread().getName());
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("method1 exec after-- threadName:" + Thread.currentThread().getName());
        }

        synchronized static void method2() {
            System.out.println("method2 exec before -- threadName:" + Thread.currentThread().getName());
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("method2 exec after-- threadName:" + Thread.currentThread().getName());
        }
    }

    //synchronized(xxx.class)加鎖, 不管線程中傳入的是不是同一個對象,都是同步
    public static void main(String[] args) {
        new Thread1().start();
        new Thread2().start();
    }
}
//執行結果
method1 exec before -- threadName:Thread-0
method1 exec after-- threadName:Thread-0
method2 exec before -- threadName:Thread-1
method2 exec after-- threadName:Thread-1

總結:

synchronized加鎖方式 同步還是異步
synchronized void methodName() 線程中傳入的是同一個對象同步,否則異步
synchronized(this) 線程中傳入的是同一個對象同步,否則異步
synchronized(xxx.class) 不管線程中傳入的是不是同一個對象,都是同步
synchronized static void methodName() 同步
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章