首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >为什么当它是私人的时候我们不能获得锁?

为什么当它是私人的时候我们不能获得锁?
EN

Stack Overflow用户
提问于 2012-08-19 16:43:44
回答 3查看 367关注 0票数 0

为什么使锁对象私有封装锁,使客户端代码无法获得锁?

对象的本征锁

代码语言:javascript
运行
复制
   public class A{
        private final Set<Integer> set = new HashSet<Integer>();

        public synchronized void addInt(int i){
            set.add(i);
        }
   }

私人锁

代码语言:javascript
运行
复制
   public class B{
        private final Set<Integer> set = new HashSet<Integer>();

        public void addInt(int i){
             synchronized(set){
                  set.add(i);
             }
        }
   }
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2012-08-19 17:08:43

另外一个类根本无法访问set,因为它是私有的。在许多其他人都不能做的事情中,因为他们没有访问该引用的权限,同步是其中之一。

如果getter直接返回该引用(不包装或复制对象),则其他人可以在其上同步,从而破坏私有对象上的锁的好处。

票数 3
EN

Stack Overflow用户

发布于 2012-08-19 16:51:31

在您提供的两个示例中,都使用了一个内部监视器。但是,第二个示例使用set字段的内部锁。在使用此实践时要小心:如果发布对set的引用,类之外的代码可能会在其监视器上同步,这可能导致死锁。

我认为您得到的区别是synchronized与使用java.util.concurrent.Lock API的区别。您获得的大部分内容是添加了灵活性(来自锁定文档):

同步方法或语句的使用提供了对与每个对象关联的隐式监视器锁的访问,但强制以块结构的方式进行所有锁的获取和释放:当获得多个锁时,它们必须以相反的顺序释放,而所有锁必须在获取它们的相同的词法范围内释放。 虽然同步方法和语句的作用域机制使使用监视器锁进行编程变得更加容易,并有助于避免涉及锁的许多常见编程错误,但在某些情况下,您需要以更灵活的方式处理锁。例如,一些用于遍历并发访问数据结构的算法需要使用“手对手”或“链锁定”:获取节点A的锁,然后是节点B,然后释放A和获取C,然后释放B和获取D等等。Lock接口的实现允许使用这样的技术,允许在不同的作用域中获取和释放锁,并允许以任何顺序获取和释放多个锁。

还有两个方法调用为您提供了使用lock API获取锁的更多方法:

  • lockInterruptibly:除非线程被中断,否则获取锁。
  • tryLock:只有在调用时是空闲的(可选超时)时,才能获取锁。

Java中并发性的规范引用是“'Java在实践中的并发”

票数 1
EN

Stack Overflow用户

发布于 2012-08-19 19:36:39

为什么使锁对象私有封装锁,使客户端代码无法获得锁?

老实说,我不知道这个问题的意思。

代码段之间的区别在于所使用的锁。在第一种情况下,整个方法是同步的(使用A的内部锁),而在第二种情况下,您要锁定正在试图修改的集合。也就是说,两个线程可以同时进入该方法,但1将阻止尝试获取add的锁。

该方法有两个优点:1) --它定义了锁定的粒度(对于只需要锁的长方法,在整个方法调用期间锁定会降低性能)和2) (通过锁定使其线程安全的集合)。

请注意,您可以使用任何对象作为锁:Object lock = new Object();

synchronized(lock){

代码语言:javascript
运行
复制
`//do something`

}

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/12028190

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档