在Java中,我应该使用什么作为同步语句的锁对象

在Java中,我应该使用什么作为同步语句的锁对象,java,object,synchronization,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) {

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

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

}
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
        }
    }

}
示例#2.

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
        }
    }

}
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
        }
    }

}

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

在第一种情况下,您锁定的对象只有在这个方法中才知道,所以其他人不太可能使用相同的对象来锁定,所以这种锁定几乎是无用的。第二种变体对我来说更有意义


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

假设
Main
不打算成为“泄漏的抽象”,这里是第一个示例和第二个示例之间的最小区别

使用
对象
可能比使用其他类更好,因为
对象
实例没有字段,因此更小。而
对象
-as-lock习惯用法清楚地表明
lock
变量只打算用作锁

话虽如此,锁定一个其他人都看不到的对象肯定有好处。
Main
方法在
Main
上同步(例如
this
)的问题在于,其他不相关的代码也可能出于不相关的目的在其上同步。通过在专用(私有)锁对象上同步,可以避免这种可能性


针对该评论:


这两种情况有很大区别。首先,锁定要操纵的对象。在第二种情况下,您将锁定与被操纵对象没有明显关系的其他对象。第二种情况需要更多的空间,因为您必须分配(否则未使用的)对象,而不是使用正在保护的现有实例

我认为您的假设是错误的,
MyClass
是需要保护的数据结构。事实上,问题并没有这么说。实际上,该示例的编写方式意味着锁旨在保护整个
Main
类。。。不仅仅是它国家的一部分。在这种情况下,有一个明显的联系

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


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

不同之处在于锁的类别及其范围 -这两个主题与同步非常正交

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

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


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

这两个示例都不是很好的同步实践。
lock对象
应作为私有字段放置在
MyClass
中。

更改对象变量时,语句同步非常有用

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


在示例2中,您正在修改
myClass
,但锁定了
lock
对象,这是胡说八道。

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

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

当您处理属于单个类的静态数据时,就不那么明显了。在这种情况下,您通常希望锁定该类

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

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

无论您选择什么,都必须在对受保护数据的所有引用中保持一致。在引用/修改相同数据时,您不希望在一种情况下锁定对象A,在另一种情况下锁定对象B。(请不要陷入这样的陷阱:你可以锁定一个任意的类A实例,而这会以某种方式锁定另一个类A实例。这是一个典型的初学者错误。)

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