关于Java同步的问题
Java文档说“同一个对象上的两个同步方法的调用不可能交错”。 我需要知道的是,synchronized是否还会阻止同一类的两个不同实例中的同步方法进行交错。
例如,类Worker具有名为process()的方法。 我们有几个Worker在自己的线程中运行的实例。 我们希望防止同时运行process()方法的多个实例。 会同步吗?
谢谢。
没有; synchronized
仅防止多个线程在同一实例中同时执行该方法。 如果你有n个实例,那么可能有n个线程,每个线程在其中一个实例中执行该方法。
如果需要确保只有一个线程可以跨所有实例执行该方法,则应使该方法为static
,或使该方法不synchronized
,而是使用方法内的synchronized
块来锁定private static
字段。
编辑:请注意,在private
实例变量上进行synchronized
适合使用synchronized
方法或在this
上进行同步,并且对private static
实例变量的锁定优先于具有static synchronized
方法或在this.getClass()
上同步的实例方法this.getClass()
。 原因是this
和this.getClass()
是可以在整个程序中访问的对象引用,因此任何人都可以在这些对象上进行同步,从而阻止想要调用方法的线程。
编辑:另外,请参阅下面@ Cowan的评论 – 摘要:如果你真的想要锁定类,你可能想要使用synchronized (Worker.class)
而不是synchronized (this.getClass())
synchronized (Worker.class)
synchronized (this.getClass())
,这取决于你想要的效果在子类化的情况下。
不,同步不会这样做。 更具体地说,在实例级别上同步不会这样做。 相反,您必须在类级别上进行同步。
例如,而不是:
public synchronized method() { //do stuff }
你必须编码为:
public void method() { synchronized(this.getClass()) { //do stuff } }
除非该方法是static
。 synchronized
非静态方法会锁定调用它的对象(实例),而不是类。
同步静态方法会锁定类,因此可能有所帮助 – 但它通常不太实用。
你可以做的是在你的类中有一个静态成员对象,并在你的process
方法中对该(类 – 全局)对象执行一个synchronized块。
不,该方法同步锁定特定对象(’this’),因此同一类的2个实例将锁定不同的对象。
如果要跨类的所有实例进行同步,则需要在方法中使用synchronized块,锁定静态最终对象。
我略微不同意Aasmund – 虽然同时有点同意:如果你使用这样的结构:
class Worker { ... public synchronized void process() {...} }
然后Aasmund是对的 – 这不会阻止Worker
类的多个实例并行执行process()
。 但是,您可以使用synchronized
关键字仍然在静态成员上进行同步,以防止发生这种情况:
class Worker { static Object o = new Object(); ... public void process() { synchronized(o) { ...//perform the work here } }
任何时候只有一个线程可以锁定对象。
同步方法尝试保持对实例的锁定。 另一个线程也可以锁定同一个类的另一个实例。 另一个线程无法进入同一实例的另一个同步方法。 即它不是被锁定的方法。
但是,一个线程可以进入非同步方法,而另一个线程持有该对象的锁。 仅保护同步方法。
静态同步方法获取Class而不是对象的锁定。 但是,除非使用不同的对象,否则遵循与非静态方法相同的规则。
注意:即使您可以编写似乎使用实例的代码,静态方法也没有“实例”。 例如instance.staticMethod()
如果将方法process
静态,则只允许同时调用该方法。
如果那是不可能的,那就有一个静态变量,比如Integer lock
; 并在方法process
使用synchronized (lock)
。 那是
process() { synchronized (lock) { // all your code } }