synchronized使用

本文深入解析synchronized关键字的多种用法及其对线程安全的影响,并介绍了一种通过双检查锁定提高效率的方法。

最近在查阅一些源码时,看到里边频繁用到了synchronized这个锁,从而在此重新理解并分析下这个锁的用法

首先先明确一个点:锁的出现一定是为了解决共享资源的操作问题,若不存在共享资源,则没有锁的必要。

在下文中,我们将RESOURCES假定为一个共享资源,我们以下所有的用法都来解决RESOURCES中某个元素的获取,若不存在,则创建该元素并放入共享资源RESOURCES。

我们看具体用法

1、

    public synchronized Resource getResource(String namespace) {
        Resource resource= RESOURCES.get(namespace);

        if (resource == null) {
            resource = createResource(namespace);
            RESOURCES.put(namespace, resource);
        }

        return resource;
    }

synchronized修饰一个普通对象方法上,此时锁定的是当前对象,即:若多线程下,此对象只有一份(单列),则此处可以满足线程安全

2、

public Resource getResource(String namespace) {
        synchronized(this){
            Resource resource = RESOURCES.get(namespace);

            if (resource == null) {
                resource = createResource(namespace);
                RESOURCES.put(namespace, resource);
            }
            return resource;
        }
}

synchronized修饰this代码块,此时锁定的也是当前对象,此用法与1不同的是,将锁的粒度降低至方法内部,而不是整个方法,若在此方法内部存在其他逻辑处理,则可提升执行效率,但同样的,必须保证多线程下对象唯一,否则无法保证线程安全。

3、

public synchronized static Resource getResource(String namespace) {
        Resource resource = RESOURCES.get(namespace);

        if (resource == null) {
            resource = createResource(namespace);
            RESOURCES.put(namespace, resource);
        }
        return resource;
}

synchronized修饰类中的静态方法,此时锁定的是整个类,多线程环境下,无需保证此类的对象是否唯一就可满足线程安全的需求。

4、

public Resource getResource(String namespace) {
        synchronized(SynchronizedTest.class){
            Resource resource = RESOURCES.get(namespace);
            if (resource == null) {
                resource = createResource(namespace);
                RESOURCES.put(namespace, resource);
            }
            return resource;
        }
}

synchronized修饰类的代码块,此时锁定的也是整个类,此用法与3不同的是,将锁的粒度降低至方法内部,而不是整个方法,若在此方法内部存在其他逻辑处理,则可提升执行效率。

以上几种,若正确使用,都可保证线程安全,但都不是最优的使用方式,我们可以看到,不论哪种,为了获取RESOURCES资源中的元素,每次都会经过锁,哪怕是当前元素已存在

我们来看下以下用法,这也是我在浏览一些源码时,各位前辈所使用的方式

 public Resource getResource(String namespace) {
        Resource resource = RESOURCES.get(namespace);

        if (resource == null) {
            synchronized (this) {
                resource = RESOURCES.get(namespace);

                if (resource == null) {
                    resource = createResource(namespace);
                    RESOURCES.put(namespace, resource);
                }
            }
        }

        return resource;
}

大家看到,这种用法,在锁之外多加了一次get操作,若此资源已经存在,则不会经过锁,从而提升了效率,只有真正需要修改资源的情况才会进入锁的逻辑。当然,此处是锁定类还是锁定对象,可根据实际情况调整。

 

以上就是自己对于synchronized关键字的一个小结,此经验充份说明了看源码的好处。我们可以多积累前人的经验与智慧,从而不断提升自己。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值