我应该将什么用作Java中synchronized语句的锁对象

时间:2013-02-06 17:46:46

标签: java object synchronization

有人能解释一下这些例子之间的区别吗?

示例#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
        }
    }

}

如果在修改变量时需要注意同步,我应该使用什么作为监视器锁?

6 个答案:

答案 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中。