有人能解释一下这些例子之间的区别吗?
示例#1。
public class Main {
private Object lock = new Object();
private MyClass myClass = new MyClass();
public void testMethod() {
// TODO Auto-generated method stub
synchronized (myClass) {
// TODO: modify myClass variable
}
}
}
示例#2。
package com.test;
public class Main {
private MyClass myClass = new MyClass();
private Object lock = new Object();
public void testMethod() {
// TODO Auto-generated method stub
synchronized (lock) {
// TODO: modify myClass variable
}
}
}
如果在修改变量时需要注意同步,我应该使用什么作为监视器锁?
答案 0 :(得分:3)
更改对象的变量时,语句同步非常有用。
您正在更改myClass
的变量,以便锁定myClass
对象。如果您要更改lock
中的内容,则需要锁定lock
对象。
在示例#2中,您正在修改myClass
,但锁定lock
对象是无意义的。
答案 1 :(得分:2)
在第一种情况下,您锁定仅在此方法中已知的对象,因此其他任何人都不可能使用相同的对象来锁定,因此这种锁几乎是无用的。第二种变体对我来说更有意义。
同时,myClass变量也只在此方法中已知,因此其他线程不太可能访问它,因此可能根本不需要锁定。需要更完整的例子来说明。
答案 2 :(得分:2)
假设Main
并非旨在成为“漏洞抽象”,这里的第一个和第二个例子之间的差别很小。
使用Object
而不是其他类可能更好,因为Object
实例没有字段,因此更小。并且Object
- 锁定惯用法清楚地表明lock
变量仅用作锁定。
话虽如此,锁定一个别人什么都看不见的物体有一定的优势。在Main
(例如Main
)上同步的this
方法的问题在于,其他不相关的代码也可以在其上进行同步,以实现不相关的目的。通过在专用(私有)锁定对象上进行同步,可以避免这种可能性。
回应评论:
两种情况存在重大差异。在第一个中,您将锁定要操作的对象。在第二个中,您将锁定一些与被操纵对象没有明显关系的其他对象。第二种情况需要更多空间,因为您必须分配(否则未使用)对象,而不是使用您正在保护的已存在的实例。
我认为你正在做出一个不正确的假设 - MyClass
是需要保护的数据结构。事实上,该问题没有说明。实际上,编写示例的方式意味着锁定旨在保护整个Main
类......而不仅仅是其状态的一部分。在这种情况下,有明显的联系......
如果MyClass
是一个漏洞抽象,允许其他代码获取其Main
引用,那么锁定myClass
的唯一情况就是如此。这将是糟糕的设计,尤其是在多线程应用程序中。
根据修订历史,我很确定这不是OP的意图。
答案 3 :(得分:1)
区别在于锁的类及其范围 - 这两个主题与同步非常正交
具有不同类别的对象可能具有不同的大小
不同范围内的对象可能在不同的上下文中可用
基本上两者在同步方面的行为相同
答案 4 :(得分:1)
通常,您希望锁定正在操作的数据的“根”对象。例如,如果您要从对象A中的字段中减去一个值并将该值添加到对象B,则需要锁定一些在A和B之间以某种方式常见的对象(至少按照惯例),可能是“所有者“两个人的对象。这是因为你正在进行锁定以保持单独数据之间的一致性“契约” - 锁定的对象必须是通用的,并且在概念上包含必须保持一致的整个数据集。
当然,简单的情况是当你在同一个对象中修改字段A和字段B时,在这种情况下锁定该对象是显而易见的选择。
当你处理属于单个类的静态数据时,不太明显。在这种情况下,您通常希望锁定该类。
单独的“监视器”对象 - 仅用作可锁定实体 - 在Java中很少需要,但可能适用于两个并行数组的元素,在这两个数组中,您希望保持元素N之间的一致性这两个数组。在这种情况下,类似监视器对象的第三个数组可能是合适的。
(请注意,在制定一些规则时,这只是一个“快速破解”。人们可以遇到许多细微之处,特别是在尝试允许对访问量很大的数据进行最大程度的并发访问时。在高性能计算之外很少见。)
无论您选择什么,在所有对受保护数据的引用中选择一致至关重要。在引用/修改相同数据时,您不希望在一个案例中锁定对象A而在另一个案例中锁定对象B. (请不要陷入这样的陷阱,认为你可以锁定A类的任意实例,并以某种方式锁定另一个A类实例。这是一个经典的初学者的错误。)
在上面的示例中,您通常希望锁定创建的对象,假设您确保的一致性都是该对象的内部。但请注意,在此特定示例中,除非MyClass的构造函数以某种方式让对象地址“转义”,否则根本不需要锁定,因为其他线程无法获取新对象的地址。
答案 5 :(得分:0)
这两个例子都不是很好的同步练习。
lock Object
应作为私人字段放在MyClass
中。