2012-07-30 77 views
2

我的问题是关于在Java中锁定对象实例。 我有以下方法,可以在同一时间由多个线程调用。我选择锁定一个对象实例,因为我希望允许并发处理,只要一次只能由一个线程访问一个实例。对对象实例的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); 
    } 
} 
..... 
} 
+1

这看起来像一个代码气味,诚实。为什么'TestForInternals_0'有两种不同的可能类型? – 2012-07-30 13:33:21

+0

我试图简化张贴的代码,并把它弄得一团糟......道歉! – user1563047 2012-07-30 13:37:14

+0

好吧,我想我现在看到它......但这仍然有点臭。也许你可以使用'enum'作为消息,并在枚举方法中指定不同的行为? – 2012-07-30 13:38:41

回答

1

假设:

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

只是检索到现有的对象的引用,并且不会创建一个新的实例,则该对象的监视器将被锁定,你在做什么是有效的。

3

对象类型的变量只是一个参考对象;这是锁定的对象,而不是参考。如果且仅当所有可能读取或写入相关数据的客户端都同意只有在锁定同一对象时才这样做,则此类锁定才有效。无论是否是局部变量都无关紧要 - 它是否每个人都使用与锁相同的对象。

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

0

只要修改你做context不影响什么将由getInstance方法返回

1

是不是真的有足够的“背景”您的代码就可以了(双关语不打算)你的问题是当然,如果这段代码完全是线程安全的。但是,如果我们假设1)message是一个局部变量,并且2)访问或更新上下文对象的所有内容都是在同步对象时执行的,则此片段中的代码是线程安全的。


我一直在阅读的建议从来没有锁定对象可能会改变,我突然不能确定这是否是我在做什么毕竟!

你应该担心什么是这样的:

public class Foo { 
    // some state variables 

    public Object lock = new Object(); 

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

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

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

0

据我所知,你的方法processInput被调用,你的synchonized块确保context.evaluateContextRules(...)只在一个线程中运行。

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

其他人提到你必须确保你锁定了对象,而不是对象的引用。那么,因为它看起来在你的代码中,你在同一个对象上同步你调用一个方法,所以这不应该是一个问题。