synchronized的对象锁和类锁的区别

833 阅读2分钟

synchronized可以锁对象,代码块,类对象 ,那么他们用起来会有区别吗,这里我们用实际代码来探究下

package com.example.hxk.thread.synchroized;

public class SyncTest1 {

    // synchronized修饰实例方法
    public synchronized void test1() {
        for (int i = 0; i < 5; i++) {
            System.out.println(Thread.currentThread().getName() + " : " + i);
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    // synchronized代码块
    public void test2() {
        synchronized (this) {
            for (int i = 0; i < 5; i++) {
                System.out.println(Thread.currentThread().getName() + " : " + i);
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public static void main(String[] args) {
        SyncTest1 t1 = new SyncTest1();

        new Thread(new Runnable() {
            @Override
            public void run() {
                t1.test1();
            }
        }, "thread1").start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                t1.test2();
            }
        }, "thread2").start();
    }
}

运行结果:

thread1 : 0
thread1 : 1
thread1 : 2
thread1 : 3
thread1 : 4
thread2 : 0
thread2 : 1
thread2 : 2
thread2 : 3
thread2 : 4

这里thread2会等thread1运行完成才会开始运行,说明thread1和thread2请求的是同一把锁,也就说明了 synchronized代码块锁当前对象和锁实例方法,他们的效果是一样的, 锁的都是当前对象。

然后我们再来看看类锁,修改代码如下

package com.example.hxk.thread.synchroized;

public class SyncTest1 {

    // 修饰静态方法
    public static synchronized void test1() {
        for (int i = 0; i < 5; i++) {
            System.out.println(Thread.currentThread().getName() + " : " + i);
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    // 修饰类对象
    public void test2() {
        synchronized (SyncTest1.class) {
            for (int i = 0; i < 5; i++) {
                System.out.println(Thread.currentThread().getName() + " : " + i);
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public static void main(String[] args) {
        SyncTest1 t1 = new SyncTest1();

        new Thread(new Runnable() {
            @Override
            public void run() {
                SyncTest1.test1();
            }
        }, "thread1").start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                t1.test2();
            }
        }, "thread2").start();
    }
}


运行结果:

thread1 : 0
thread1 : 1
thread1 : 2
thread1 : 3
thread1 : 4
thread2 : 0
thread2 : 1
thread2 : 2
thread2 : 3
thread2 : 4

这里可以看到thread2也是被thread1阻塞,所以他们持有的是同一把锁,也就说明synchronized修饰静态方法和锁类对象,他们的效果是一样的。 接下来我们同时用类锁和对象锁试试,代码如下

package com.example.hxk.thread.synchroized;

public class SyncTest1 {

    // 修饰静态方法
    public static synchronized void test1() {
        for (int i = 0; i < 5; i++) {
            System.out.println(Thread.currentThread().getName() + " : " + i);
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    // 修饰类对象
    public synchronized void test2() {
        for (int i = 0; i < 5; i++) {
            System.out.println(Thread.currentThread().getName() + " : " + i);
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        SyncTest1 t1 = new SyncTest1();

        new Thread(new Runnable() {
            @Override
            public void run() {
                SyncTest1.test1();
            }
        }, "thread1").start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                t1.test2();
            }
        }, "thread2").start();
    }
}

运行结果:

thread1 : 0
thread2 : 0
thread1 : 1
thread2 : 1
thread2 : 2
thread1 : 2
thread2 : 3
thread1 : 3
thread2 : 4
thread1 : 4

运行结果是交替进行的,说明对象锁和类锁锁的不是同一个锁,他们是两个锁,互不影响

总结:
1,synchronized修饰在实例方法上和synchronized(this){} 同步代码块效果是一样的
2,synchronized修饰在静态方法上和 synchronized (SyncTest1.class) {} 同步代码块效果是一样的
3,synchronized修饰在实例方法表示锁的是当前对象,修饰静态方法表示锁的是类对象(一个类在jvm中只有一个class对象)