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() 同步
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章