【问题标题】:Java multithreading synchronized method with two threads具有两个线程的Java多线程同步方法
【发布时间】:2013-11-12 07:59:10
【问题描述】:

我有一个非常简单的代码但无法理解。

    public class Test extends Thread {
    
        public synchronized void testPrint() {
            System.out.println("I am sleeping..."
                    + Thread.currentThread().getName());
            try {
                Thread.sleep(3000);
                System.out.println("I am done sleeping..."
                        + Thread.currentThread().getName());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    
        public void run() {
            Test t = new Test();
            t.testPrint();
    
            System.out.println("I am out..." + Thread.currentThread().getName());
        }
    
        public static void main(String[] args) {
            Test t1 = new Test();
            Test t2 = new Test();
    
            t1.start();
            t2.start();
    
        }
    }

这是我的问题

当两个线程执行Test t = new Test()时,这是否会创建两个同名的不同对象?多线程的这一行会发生什么?

我得到低于结果,

我在睡觉...线程0

我在睡觉...线程 1

我睡完了……Thread-0

我出去了...线程0

我睡完了……Thread-1

我出去了...线程 1


从输出来看,这肯定意味着创建了两个对象,这就是为什么两个线程都可以进入同步方法的原因。希望我的理解是正确的? 系统如何维护这两个对象?

【问题讨论】:

  • synchronized 不同步方法,它同步对象。在您的情况下,这两个线程有​​自己的对象并且没有共享数据,因此它们没有理由进行交互。是的new 创建了一个新对象。

标签: java multithreading synchronized


【解决方案1】:

使用您当前的方法,您可以确保对于Test 的每个实例,方法testPrint() 不能同时运行。这一切都取决于你想做什么。我假设您想保护testPrint() 方法不同时在多个线程中运行,并具有多个Test 实例。

目前您直接在方法上使用synchronized 关键字。这导致使用对象本身(Test 的实例)进行同步。

您应该在 Test 的实例之间共享的另一个对象上进行同步(例如,您可以将锁定对象设为静态)。

还请注意,通常最好只实现Runnable 接口,然后将实现传递给线程。 另外,您不必每次运行时都创建Test 的新实例(我不明白这样做的目的),我将其注释掉。

public class Test extends Thread {
  // could also use a static monitor instead.
  // private static final Object monitor = new Object();
  private final Object monitor;

  public Test(final Object monitor) {
    this.monitor = monitor;
  }

  public void testPrint() {
    synchronized (monitor) {
      System.out.println("I am sleeping..." + Thread.currentThread().getName());
      try {
        Thread.sleep(3000);
        System.out.println("I am done sleeping..." + Thread.currentThread().getName());
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }
  }

  public void run() {
    //Test t = new Test(monitor);
    //t.testPrint();
    testPrint();
    System.out.println("I am out..." + Thread.currentThread().getName());
  }

  public static void main(String[] args) {
    // synchronization will happen on this object.
    final Object monitor = new Object();

    Test t1 = new Test(monitor);
    Test t2 = new Test(monitor);

    t1.start();
    t2.start();

  }
}

【讨论】:

    【解决方案2】:
    Test t = new Test()
    

    这将在堆中创建一个对象,并将引用放置在堆栈中。

    在您的示例中,您根本不需要 synchronized 方法,因为您没有在不同线程之间共享实例。

    【讨论】:

      【解决方案3】:

      您正在创建两个不同的对象,它们将具有两个不同的监视器,在它们上将获取锁。由于两个线程都在不同的对象上工作,因此无法同步。

      你可以试试

      public class Test extends Thread {
      
      Object obj;
      
      public Test(Object obj){
          this.obj = obj;
      }
      
      public synchronized void testPrint() {
          System.out.println("I am sleeping..."
                  + Thread.currentThread().getName());
          try {
              Thread.sleep(3000);
              System.out.println("I am done sleeping..."
                      + Thread.currentThread().getName());
          } catch (InterruptedException e) {
              e.printStackTrace();
          }
      }
      
      public void run() {
          ((Test)obj).testPrint();
          System.out.println("I am out..." + Thread.currentThread().getName());
      }
      
      public static void main(String[] args) {
      
          Object obj = new Test(null);
      
          Test t1 = new Test(obj);
          Test t2 = new Test(obj);
      
          t1.start();
          t2.start();
      
      }
      }
      

      输出是

      I am sleeping...Thread-1
      I am done sleeping...Thread-1
      I am out...Thread-1
      I am sleeping...Thread-2
      I am done sleeping...Thread-2
      I am out...Thread-2
      

      正如预期的那样。

      【讨论】:

        【解决方案4】:

        当您运行Test t = new Test() jvm 在堆上创建新对象并将带有指向该对象的链接的变量 t 放在当前线程的堆栈上。
        当您在两个或多个不同线程中运行该代码时,每个线程都有自己的堆栈,因此每个线程都创建自己的变量 t 和对象 Test

        【讨论】:

        • 这里有两个线程将进入运行,这会创建两个对象还是一个对象?如果它在两个各自的线程中创建两个对象,我如何在后续代码中使用这两个对象?即两个对象都具有相同的名称 't' !或者范围仅在那些线程中?如果线程共享内存,这些对象应该可以被其他人和主线程访问......那我该如何使用它呢?如果它只创建一个具有 2 个引用的对象,那么两个线程不应同时进入该方法.. 对吗?但输出显示不同。
        • 有两个对象,但没有从其他代码到它们的链接。在 java 中,您不能直接访问内存 - 您应该将链接保存到变量或属性中的对象。当您将链接保存到变量时,它不能从其他线程访问,当在属性中时 - 它可以被访问。
        • 好的,谢谢,我想我明白了。唯一的问题是,如果我在代码中使用“t”对象,那么它将引用哪个对象?由线程 1 或 2 创建?我怎么知道创建了哪些,因为对象的状态可能不同。这段代码有缺陷吗?
        • 在您的代码中,您使用在current 线程中创建的对象。它本身不是缺陷,它取决于你的目标
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多