关于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() 。 原因是thisthis.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 } } 

除非该方法是staticsynchronized非静态方法会锁定调用它的对象(实例),而不是类。

同步静态方法会锁定类,因此可能有所帮助 – 但它通常不太实用。

你可以做的是在你的类中有一个静态成员对象,并在你的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 } }