Java synchronized(this)与synchronized(object)的区别

前言

最近在看Glide 4.11的源码时,无意间看到以下一段代码。我就纳闷,为什么不直接用this就好?非要用Object对象,多此一举呢?,后面经一波探究,发现了不同点。

 public static class SynchronizedPool<T> extends SimplePool<T> {
 
        private final Object mLock = new Object();
        
        public SynchronizedPool(int maxPoolSize) {
            super(maxPoolSize);
        }
        @Override
        public T acquire() {
            synchronized (mLock) {
                return super.acquire();
            }
        }
        @Override
        public boolean release(@NonNull T element) {
            synchronized (mLock) {
                return super.release(element);
            }
        }
    }

一,同步作用相同。
都可以实现,多线程对类的同一个实例的方法的同步,都属于对象锁的范畴。

二,锁对象不同。
synchronized(this),锁的对象是this,是类的实例。
synchronized(object),锁的对象是object。

 class Test{
    private final Object object = new Object();
    public void print(){
        synchronized (object){
            System.out.println("xxxx");
        }
    }
}
 class Test{
    public void print(){
        synchronized (this){
            System.out.println("xxxx");
        }
    }
}

三,那为什么要用 synchronized (object) 这种方式,去多创一个object对象呢?让我们先看一下以下代码。


class STest{
 
    public void print(){
        synchronized (this){
            System.out.println("xxxx");
        }
    }
}

public class SynchronizeMain {

    public static void main(String[] args) throws InterruptedException {

        STest sTest = new STest();

        // Thread 1
        Thread t1 = new Thread(() -> {
            sTest.print();
        });

        // Thread 2
       Thread t2 = new Thread(() -> {

           try {
               synchronized (sTest){
                   while (true);
               }
           } catch (Exception e) {
               System.out.println("Exception="+e.getMessage());
           }

        });

       t2.start();
       t1.start();
    }
}

输出结果是什么都没有! 原因在于,synchronized(this)的锁对象是this,如果使用这种方式,一旦锁对象(实例)被别人获取,别人只要开个线程像Thread 2 一样,那你的Thread 1,这个正常的工作线程,就永远得不到执行,造成死锁。让我们再看看另一个例子:


 class STest{

    private final Object object = new Object();
    public void print(){
        synchronized (object){
            System.out.println("xxxx");
        }
    }
}

public class SynchronizeMain {

    public static void main(String[] args) throws InterruptedException {

        STest sTest = new STest();

        // Thread 1
        Thread t1 = new Thread(() -> {
            sTest.print();
        });

        // Thread 2
       Thread t2 = new Thread(() -> {

           try {
               synchronized (sTest){
                   while (true);
               }
           } catch (Exception e) {
               System.out.println("Exception="+e.getMessage());
           }

        });

       t2.start();
       Thread.sleep(1000);
       t1.start();
    }
}

输出结果是 xxxx! 原因在于,synchronized(object),锁的对象是object。所以,你拿到了sTest的实例,也不会影响到Thread1的正常执行。

四,如果我通过反射,获取object变量,传入Thread2里面,会怎么样呢?

如果是这样的话,那一样可以使得Thread 1,这个正常的工作线程,永远得不到执行,造成死锁。Talk is cheap, Show me code:


 class STest{

    private final Object object = new Object();
    public void print(){
        synchronized (object){
            System.out.println("xxxx");
        }
    }
}

public class SynchronizeMain {

    public static void main(String[] args) throws InterruptedException {

        STest sTest = new STest();

        // Thread 1
        Thread t1 = new Thread(() -> {
            sTest.print();
        });

        // Thread 2
       Thread t2 = new Thread(() -> {

           try {
               synchronized (getPrivateField(sTest,"object")){
                   while (true);
               }
           } catch (Exception e) {
               System.out.println("Exception="+e.getMessage());
           }

        });

       t2.start();
       Thread.sleep(1000);
       t1.start();
    }

    public static Object getPrivateField(Object instance, String filedName) throws NoSuchFieldException, IllegalAccessException {
        Field field = instance.getClass().getDeclaredField(filedName);
        field.setAccessible(true);
        return field.get(instance);
    }

}

输出结果是什么都没有! 原因在于,synchronized(object)的锁对象是object,而object被Thread2占用了。


总结

选择锁对象时,要考虑到锁对象的安全性,尽量避免锁对象暴露出去。很多开源库采用的同步方法块的方法是通过设置object来实现。虽然,它仍然可以通过反射来破解。但却增强了一层保障,以及一些可能存在人为的误操作,导致的死锁。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值