2

我的问题是关于锁定 Java 中的对象实例。我有以下方法可以被多个线程同时调用。我选择锁定一个对象实例,因为我希望允许并发处理,只要一个实例一次只能由一个线程访问。

我的简化代码是这样的,我基本上锁定了一个局部变量。这真的能满足我的需要吗?我一直在阅读建议不要锁定可能会改变的对象,我突然不确定这是否是我正在做的事情!

谢谢!

编辑:

哦,天哪……我只是意识到我试图简化发布代码的尝试可能会有点误导。

我将之前调用“getInstance”的方法重命名为其他名称(“getFromMap”),以证明该方法调用是自定义代码,它返回对哈希图中对象的引用。

之前的答案还会成立吗?为混乱道歉!

public boolean processInput(...) {
if(message == 1) {
    Class_0 context = (Class_0)Class_0.getFromMap("xyz");
    synchronized(context) {
        context.setContextParams("abc");
       context.evaluateContextRules(message, this);
    }
} else if(message == 2) {
    Class_1 context = (Class_1)Class_1.getFromMap("efg");
    synchronized(context) {
        context.setContextParams("abc");
        context.evaluateContextRules(message, this);
    }
}
.....
}
4

5 回答 5

3

对象类型的变量只是对对象的引用;锁定的是对象,而不是引用。当且仅当所有可能读取或写入相关数据的客户端都同意这样做时,这样的锁才有效,只有当持有同一对象的锁时。它是否是一个局部变量并不重要——重要的是每个人是否都在使用同一个对象作为锁。

在这里,您的物品似乎来自某种工厂;如果getInstance(X)总是为给定的X值返回相同的对象,那么你可能很好。

于 2012-07-30T13:30:26.787 回答
1

假如说:

Class_1 context = (Class_1)TestForInternals_0.getInstance("efg");

只需检索对现有对象的引用而不创建新实例,然后该对象的监视器将被锁定并且您正在做的事情是有效的。

于 2012-07-30T13:28:42.280 回答
1

您的问题中没有足够的“上下文”(双关语不是有意的)来确定此代码是否完全是线程安全的。

但是,如果我们假设 1)message是一个局部变量,并且 2) 访问或更新上下文对象的所有内容在对象上同步时都会这样做,那么此片段中的代码是线程安全的。


我一直在阅读建议不要锁定可能会改变的对象,我突然不确定这是否是我正在做的事情!

你应该担心的是这样的:

public class Foo {
    // some state variables

    public Object lock = new Object();

    public void doSomething(...) {
        synchronized (lock) {
            ....
        }
    }
}

这可能是不安全的。lock如果某些东西在正确的时间改变了 的值,并且同一Foo实例上的两个操作最终可能会使用不同的锁对象进行同步。这可能导致涉及Foo状态的操作无法正确同步。

在您的示例中,同步context似乎是针对上下文对象本身的操作,因此上述问题不适用。

于 2012-07-30T13:34:41.490 回答
0

据我了解,正在调用您的方法 processInput 并且您的同步块确保 context.evaluateContextRules(...) 仅在一个线程中运行。

如果这是您的目标,那么是的,您的代码就是这样做的。

其他人提到您必须确保锁定对象,而不是对对象的引用。好吧,正如它在您的代码中所看到的那样,您正在同步调用方法的同一个对象,所以这不应该是一个问题。

于 2012-07-30T13:54:44.930 回答
0

只要您所做的修改context不影响getInstance方法返回的内容,您的代码就可以工作

于 2012-07-30T13:33:51.233 回答