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来实现。虽然,它仍然可以通过反射来破解。但却增强了一层保障,以及一些可能存在人为的误操作,导致的死锁。

  • 17
    点赞
  • 57
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
系统根据B/S,即所谓的电脑浏览器/网络服务器方式,运用Java技术性,挑选MySQL作为后台系统。系统主要包含对客服聊天管理、字典表管理、公告信息管理、金融工具管理、金融工具收藏管理、金融工具银行卡管理、借款管理、理财产品管理、理财产品收藏管理、理财产品银行卡管理、理财银行卡信息管理、银行卡管理、存款管理、银行卡记录管理、取款管理、转账管理、用户管理、员工管理等功能模块。 文重点介绍了银行管理的专业技术发展背景和发展状况,随后遵照软件传统式研发流程,最先挑选适用思维和语言软件开发平台,依据需求分析报告模块和设计数据库结构,再根据系统功能模块的设计制作系统功能模块图、流程表和E-R图。随后设计架构以及编写代码,并实现系统能模块。最终基本完成系统检测和功能测试。结果显示,该系统能够实现所需要的作用,工作状态没有明显缺陷。 系统登录功能是程序必不可少的功能,在登录页面必填的数据有两项,一项就是账号,另一项数据就是密码,当管理员正确填写并提交这二者数据之后,管理员就可以进入系统后台功能操作区。进入银行卡列表,管理员可以进行查看列表、模糊搜索以及相关维护等操作。用户进入系统可以查看公告和模糊搜索公告信息、也可以进行公告维护操作。理财产品管理页面,管理员可以进行查看列表、模糊搜索以及相关维护等操作。产品类型管理页面,此页面提供给管理员的功能有:新增产品类型,修改产品类型,删除产品类型。
### 回答1: synchronized (this) 和其他变量的主要区别在于锁定对象的范围不同。 synchronized (this) 是在当前对象实例上锁定,即锁定当前对象的所有同步代码块,只有获得锁的线程才能执行同步代码块,其他线程则需要等待锁的释放。 而对于其他变量的同步代码块,需要指定一个共享的对象作为锁。通常情况下,我们会使用一个私有的 final 对象作为锁,这个对象不会被改变,以避免出现死锁等问题。 总之,synchronized (this) 更加方便,适用于对当前对象实例进行同步,而其他变量的同步则需要更加小心地处理锁的范围和对象。 ### 回答2: synchronized (this)是Java用于实现线程同步的关键字,它的主要作用是确保在同一时间只有一个线程可以进入被synchronized块包裹的代码段。当一个线程进入synchronized (this)块时,它会获得当前对象的锁,其他线程在此期间无法进入该代码段,只能等待该线程执行完毕释放锁后才能够执行。 与此相比,其他变量并没有提供类似的线程同步机制。在多线程环境下,多个线程可以同时访问和修改同一个变量,没有任何机制来保证线程安全。这可能导致数据竞争和不一致性的问题。 使用synchronized (this)可以确保在同一时间内只有一个线程能够访问被synchronized包裹的代码段,从而避免了数据竞争和不一致性的问题。而其他变量则需要使用其他方式来实现线程安全性,比如使用volatile关键字、使用锁对象等。 需要注意的是,synchronized (this)是基于对象锁实现的,它只会对当前对象上锁,而不是对整个类或者其他对象上锁。因此,如果需要对整个类或者其他对象进行线程同步,需要使用其他方式,如synchronized (ClassName.class),或者使用实例化一个专门的锁对象。 总之,synchronized (this)是Java用于实现线程同步的关键字,能够确保在同一时间内只有一个线程能够进入被synchronized块包裹的代码段。而其他变量并没有提供类似的线程同步机制,需要使用其他方式来实现线程安全性。 ### 回答3: synchronized (this)是Java一种同步锁的机制,用于对当前对象实例进行同步控制。当多个线程访问同一个对象的synchronized(this)代码块时,只有一个线程能够执行该代码块,其他线程需要等待。 相比之下,其他变量的同步机制可以通过以下几种方式来实现: 1. synchronized (Object obj):通过指定一个非this对象来加锁,这个对象可以是任意的Java对象。这种方式可以实现不同线程对不同对象的互斥访问。 2. volatile变量:通过使用volatile关键字修饰变量,可以确保每个线程在访问该变量时都能读取到最新的值。这种机制适用于变量的读操作比写操作更频繁的情况。 3. Atomic类:Java.util.concurrent.atomic包提供了多种原子性的数据类型,如AtomicInteger、AtomicBoolean等。这些原子类具有自己的一些方法来保证对变量的操作是原子性的,从而避免了线程安全问题。 4. Lock接口:Java提供了Lock接口作为同步锁的另一种实现方式。与synchronized不同,Lock接口需要显式地进行加锁和释放锁的操作,可以更灵活地控制线程的同步行为。 总结来说,synchronized (this)是针对当前对象实例进行同步控制的机制,而其他的同步变量机制可以针对不同的对象实例进行同步控制,或者通过使用特定的关键字或类来实现线程安全。根据具体的线程操作,可以选择不同的同步机制来保证多线程的安全性。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值