为什么使锁对象私有封装锁,使客户端代码无法获得锁?
对象的本征锁
public class A{
private final Set<Integer> set = new HashSet<Integer>();
public synchronized void addInt(int i){
set.add(i);
}
}私人锁
public class B{
private final Set<Integer> set = new HashSet<Integer>();
public void addInt(int i){
synchronized(set){
set.add(i);
}
}
}发布于 2012-08-19 17:08:43
另外一个类根本无法访问set,因为它是私有的。在许多其他人都不能做的事情中,因为他们没有访问该引用的权限,同步是其中之一。
如果getter直接返回该引用(不包装或复制对象),则其他人可以在其上同步,从而破坏私有对象上的锁的好处。
发布于 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在实践中的并发”。
发布于 2012-08-19 19:36:39
为什么使锁对象私有封装锁,使客户端代码无法获得锁?
老实说,我不知道这个问题的意思。
代码段之间的区别在于所使用的锁。在第一种情况下,整个方法是同步的(使用A的内部锁),而在第二种情况下,您要锁定正在试图修改的集合。也就是说,两个线程可以同时进入该方法,但1将阻止尝试获取add的锁。
该方法有两个优点:1) --它定义了锁定的粒度(对于只需要锁的长方法,在整个方法调用期间锁定会降低性能)和2) (通过锁定使其线程安全的集合)。
请注意,您可以使用任何对象作为锁:Object lock = new Object();
synchronized(lock){
`//do something`}
https://stackoverflow.com/questions/12028190
复制相似问题