4

谁能解释这些例子之间有什么区别?

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

}

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

4

6 回答 6

3

假设这Main不是“泄漏抽象”,这里是第一个和第二个示例之间的最小差异。

使用 anObject而不是其他类可能会更好,因为Object实例没有字段,因此更小。Object-as-lock 习惯用法清楚地表明该变量lock仅用作锁。

话虽如此,锁定一个其他任何人都看不到的对象具有明显的优势。在(例如)Main上同步的方法的问题是其他不相关的代码也可能出于不相关的目的而在其上同步。通过在专用(私有)锁定对象上同步,您可以避免这种可能性。Mainthis


回应评论:

这两种情况有很大的不同。首先,您要锁定要操作的对象。在第二个中,您锁定了一些与被操作对象没有明显关系的其他对象。第二种情况占用更多空间,因为您必须分配(否则未使用的)对象,而不是使用您正在保护的已经存在的实例。

我认为您做出了一个错误的假设——这MyClass是需要保护的数据结构。事实上,问题并没有这么说。事实上,这个例子的写法意味着锁的目的是保护整个Main类......而不仅仅是它的一部分状态。在这种情况下,有一个明显的联系......

唯一最好锁定的MyClass情况是,如果Main是一个泄漏的抽象,它允许其他代码获取它的myClass引用。那将是糟糕的设计,尤其是在多线程应用程序中。

根据修订历史,我很确定这不是 OP 的意图。

于 2013-02-06T17:54:43.117 回答
3

更改对象的变量时,语句同步很有用。

您正在更改变量,myClass因此您想锁定myClass对象。如果要更改某些内容,lock则要锁定lock对象。

在示例 #2 中,您正在修改myClass但锁定lock对象,这是无意义的。

于 2013-02-06T17:57:58.850 回答
2

在第一种情况下,您锁定了仅在此方法中已知的对象,因此其他人不太可能使用相同的对象来锁定,因此这种锁定几乎没有用。第二种变体对我来说更有意义。

同时,myClass 变量也只有在这个方法中是已知的,所以其他线程不太可能访问它,所以这里可能根本不需要锁。需要更完整的例子才能说得更多。

于 2013-02-06T17:49:58.297 回答
1

不同之处在于锁的类别及其范围——这两个主题与同步几乎是正交的

  • 不同类的对象可能有不同的大小

  • 不同范围的对象可能在不同的上下文中可用

基本上两者在同步方面的行为相同

于 2013-02-06T17:57:05.347 回答
1

通常,您希望锁定您正在操作的数据的“根”对象。例如,如果您要从对象 A 中的字段中减去一个值并将该值添加到对象 B,您需要锁定一些在 A 和 B 之间以某种方式通用(至少按照惯例)的对象,可能是“所有者”两者的对象。这是因为您正在执行锁定以维持单独数据之间的一致性“契约”——锁定的对象必须是通用的,并且在概念上包含必须保持一致的整个数据集。

当然,最简单的情况是当您在同一个对象中修改字段 A 和字段 B 时,在这种情况下锁定该对象是显而易见的选择。

不太明显的是当您处理属于单个类的静态数据时。在这种情况下,您通常希望锁定课程。

在 Java 中很少需要单独的“监视器”对象(仅作为可锁定实体创建),但可能适用于两个并行数组的元素,您希望在其中保持两个数组的元素 N 之间的一致性. 在这种情况下,类似第三个监视器对象数组可能是合适的。

(请注意,这只是制定一些规则的“快速技巧”。人们可能会遇到许多微妙之处,尤其是在尝试允许最大程度地并发访问大量访问的数据时。但这种情况在外部很少见高性能计算。)

无论您选择什么,选择在所有对受保护数据的引用中保持一致至关重要。当引用/修改相同的数据时,您不想在一种情况下锁定对象 A 而在另一种情况下锁定对象 B。(并且请不要陷入认为您可以锁定 A 类的任意实例并且会以某种方式锁定 A 类的另一个实例的陷阱。这是一个经典的初学者错误。)

在上面的示例中,您通常希望锁定创建的对象,假设您确保的一致性是该对象的内部。但请注意,在这个特定示例中,除非 MyClass 的构造函数以某种方式让对象地址“逃逸”,否则根本不需要锁定,因为另一个线程无法获取新对象的地址。

于 2013-02-06T18:08:11.773 回答
0

这两个例子都不是很好的同步实践。lock Object应该MyClass作为私有字段放置。

于 2013-02-06T17:57:47.187 回答