【问题标题】:Does a synchronized method have to be external to a class that's using it?同步方法是否必须在使用它的类的外部?
【发布时间】:2016-08-09 20:59:13
【问题描述】:

场景 1.

同步方法是私有的,位于实现 Runnable 的类中

Main.java

public class Main { 

Thread thread1 = new Thread(new MyRunnable); 

. . . 

} 

MyRunnable.java

public class MyRunnable implements Runnable { 

. . . 

private synchronized doSomething { 

} 

场景 2。

同步方法是公共的和静态的,位于主类中

Main.java

  public class Main { 

    Thread thread1 = new Thread(new MyRunnable); 

    public synchronized static doSomething() { 

     }  

    } 

MyRunnable.java

   public class MyRunnable implements Runnable { 

    . . . 


}

问题:以上哪种情况是正确的?

我正在关注场景 2。所以我在 Main 类中有一个同步方法。这工作正常。当我将此同步方法移至 MyRunnable 类时,我没有发现任何区别。这很奇怪。我原以为它会失败。 synchronized 阻止同时访问此方法。

但是如果我实例化一个类的两个实例:

MyRunnable runnable1 = new MyRunnable();  
MyRunnable runnable2 = new MyRunnable();  

每个可运行文件都有自己的 synchronized ,而 synchronized 对编译器没有任何意义。我理解正确吗?

【问题讨论】:

  • 我觉得你的理解是对的,是的。 synchronized 应该默认为这个类的实例,用于非静态方法;如果您有两个不同的实例,它们都将能够同时输入synchronized 方法,因为它们正在查看不同的东西;这些方法具有相同名称的事实是无关紧要的。顺便说一句,当你说你“期待它失败”时 - 你期待看到什么?同步是为了避免线程冲突,这种冲突很难检测到,而且通常取决于运气。
  • 多个线程可能正在访问同一个实例,此时synchronized再次变得相关。
  • synchronized 正在定义 runtime 行为,由 JVM 确保,它不取决于编译器对其进行任何处理。话虽如此,synchronized 对象锁定类,而不是实例。我不确定你的问题到底是什么,在这里。您预计会失败/发生什么,以及何时(正常运行时间、编译时间)?
  • @Edward Peters 对于解释不明确,我深表歉意。期望它失败我的意思是 I was expecting the synchronized become regular method 。这正是我的想法if you have two different instances, they will both be able to enter the synchronized method at once, because they're looking at different things 但是我想先与专家确认这一点
  • 是的,我想在那里写static

标签: java multithreading synchronized


【解决方案1】:

synchronized 定义 运行时 行为。它在编译时什么都不做。

synchronized 方法被锁定在对象 (this) 的实例上。
static synchronized 方法被锁定在对象的Class 上。

此行为在JLS §8.4.3.6. synchronized Methods中定义

同步方法在执行之前获取监视器(第 17.1 节)。

对于类(静态)方法,使用与该方法的类的 Class 对象关联的监视器。

对于实例方法,使用与 this(调用该方法的对象)关联的监视器。

因此,在您的场景 1 中,该方法为 MyRunnable 的每个单独实例锁定,而在 场景 2 中,该方法被锁定在 Main.class 对象上(这或多或少是全局的,在同一个类加载器下是一样的)。

考虑这一点,在*场景 1 中:

MyRunnable runnable = new MyRunnable();
Thread t1 = new Thread(runnable);
Thread t2 = new Thread(runnable);

这里,t1 和 t2 都使用MyRunnable 的同一个实例,这意味着它们不能并行执行doSomething()

Thread t1 = new Thread(new MyRunnable());
Thread t2 = new Thread(new MyRunnable());

这里,t1 和 t2 可以在MyRunnable 的实例上并行执行doSomething(),因为它们锁定了实例。

场景2中,两个线程都不能并行执行doSomething(),因为它们锁定在Main.class中,并被同一个ClassLoader加载。

【讨论】:

    猜你喜欢
    • 2021-04-18
    • 2018-05-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多