【问题标题】:Executing two synchronized method by two thread in java在java中通过两个线程执行两个同步方法
【发布时间】:2018-11-06 14:09:59
【问题描述】:

假设我在类ABC 中有方法synchronized hi(){}synchronized hello(){}。两个线程t1t2 分别执行t1.hi()t2.hello()。它们可以同时执行还是有什么问题?

【问题讨论】:

  • 我认为它们不会同时执行。我认为同步方法基本上是对象本身的锁,所以一旦执行了一个方法,线程就会获取锁,因此其他线程无法再次获取锁来执行另一个同步方法。
  • 阅读synchronized 关键字和一般同步机制。还要注意ti.hi() 没有任何意义,除非ABC extends ThreadABC 的一部分。在这种情况下,t1t2 将是 2 个不同的实例,它们不会相互影响。但是,如果两个线程都在 ABCsame 实例上运行,则这两个方法不能并行执行(它们可以被调用,但一个线程必须等待) - 那是因为 @987654335 @在方法级别使用当前实例作为它的监控对象。
  • 所以 ABC 扩展了 Thread,或者两个线程在同一个 ABC 实例上工作?请更新一些代码。
  • 不清楚您在问什么:t1t2 是您的 ABC 类的两个不同实例吗?还是它们是两个不同的线程,它们都在调用属于同一实例的方法?如果您编辑问题以添加一些实际代码,这可能会有所帮助(很多!)。

标签: java multithreading synchronized


【解决方案1】:

不,同一对象中的 2 个同步方法不能同时执行:

https://docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html

来自文档:

在同一个对象上两次调用同步方法是不可能交错的。当一个线程正在为一个对象执行同步方法时,所有其他为同一对象调用同步方法的线程都会阻塞(暂停执行),直到第一个线程处理完该对象。

这里的关键是锁定对象。正如 Thomas 指出的那样,大概 t1t2 是同一类的不同实例,因此它们实际上可以同时执行 hi()hello()

如果t1t2 只是两个不同的线程在同一个对象上调用hi()hello(),那么上述语义成立并且这两个方法不能并行执行。

【讨论】:

    【解决方案2】:

    在方法声明中使用同步关键字使用隐式 对象,在静态方法的情况下是类对象,或者 实例对象本身在非静态方法的情况下。

    示例 1:

    public class A {
      public synchronized void setName() {
      //
      }
    
      public synchronized void setAge() {
      //
      }
    }
    

    假设有 2 个线程 Thread-1 和 Thread-2。
    现在 Thread-1 尝试访问 setName() 和 Thread-2 setAge()
    让 Thread-1 进入 1st 并持有密钥,Thread-2 将等待直到密钥可用。困惑吗?
    所以这里由于没有显式对象用于同步,所以使用相同的键来同步两个方法,它们是

    "A的对象,用于访问setName()方法和setAge() 分别由 Thread-1 和 Thread-2 调用”。

    A a = new A("Name", 1);
    Runnable nameR = () -> a.getName();
    Runnable ageR = () -> a.getAge();
    Thread nameThread = new Thread(nameR);
    Thread ageThread = new Thread(nameR);
    nameThread.start();
    ageThread.start();
    

    但这是个问题,因为即使拥有密钥的线程没有访问它,其他线程也无法运行其他方法。
    所以为了解决这个问题,我们需要有单独的键来独立同步 getName 和 getAge 方法。

    public class A {
    private final Object nameLock = new Object();
    private final Object ageLock = new Object();
      public void setName() {
       synchronized(nameLock) {
         //
       }
      }
    
      public synchronized void setAge() {
       synchronized(ageLock) {
         //
       }
      }
    }
    

    希望这会有所帮助!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-02-27
      • 2013-11-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多