【问题标题】:java and synchronizationjava和同步
【发布时间】:2012-09-22 12:39:18
【问题描述】:

我正在准备 SCJP 考试,但我无法完全理解同步。在第 6 行,我读到 main 中运行的线程需要锁定“b”。为什么它需要锁定这个对象?我的理解是,同步的代码块是一个保护区,任何时候只有一个线程可以进入?继续前进,main 中的线程释放此锁并等待 'b 中的线程完成其 run 方法。然后,'b' 中的线程用于通知 main 中的线程它已完成。但是,它看起来并没有在这里通知任何特定的线程。这个例子来自 Sierra 和 Bates SCJP 的书。任何可以阐明这一点的光都将不胜感激。谢谢

class ThreadA {  
    public static void main(String [] args) {  
        ThreadB b = new ThreadB();  
        b.start();  

        **synchronized(b) {  //line 6**
            try {  
                System.out.println("Waiting for b to complete...");  
                b.wait();  
            } catch (InterruptedException e) {}  
                System.out.println("Total is: " + b.total);  
            }  
        }  
    }  
}

class ThreadB extends Thread {     
    int total;  

    public void run() {  
        System.out.println("K");  
        synchronized(this) {  
            for(int i=0;i<100;i++) {  
                total += i;  
            }  
            notify();  
        }  
    }  
}

【问题讨论】:

  • 您不需要锁定该对象。但是同步一个线程是可以的。
  • b.start() 不应该在 main 的同步部分中吗?因为如果它调用 b.start() 可能会使主线程饿死,然后调度程序切换到 b 线程并在调用同步之前离开主线程。然后 b.run 获得锁,然后完成并通知。然后 main 获得锁并永远等待,因为已经调用了 notify。
  • 对不起,双重评论,但偶然发现另一个 SO 问题与指出我提出的问题完全相同的例子:link

标签: java synchronization


【解决方案1】:

在第 6 行,我读到 main 中运行的线程需要锁定“b”。为什么它需要锁定这个对象?

因为这就是那条线的作用。它获取该资源。其他线程可以获取其他同步块,但没有其他线程可以获取该对象的锁。

它似乎没有在此处通知任何特定线程。

这是真的。该程序不知道将通知哪个线程,甚至不知道是否会通知任何线程。作为开发人员,您可能会得出结论,有一个特定的线程会被通知,可能是因为它是唯一的线程等待()。

【讨论】:

    【解决方案2】:

    两个线程在这里同步在同一个Object,即bmain() 首先获取锁,然后调用b.wait(),它释放锁并等待有人在b 上调用notify()

    这意味着当 run() 方法(在本例中为 b 调用)调用 notify() 时,这将再次唤醒 main() 方法。

    因此,在b 上获得锁并不重要,重要的是两个线程都获得相同的锁,否则wait()/notify() 合作将不起作用。

    【讨论】:

      【解决方案3】:

      这是一个非常极端的案例,您不会不会这样做。
      发生的情况是 main 线程在 ThreadB 对象和 wait 上同步。
      ThreadB 完成时,会引发notify,结果main 被唤醒并继续。
      但这不是您通常会编写的代码,即使用 Thread 对象作为 synchronization
      要查看这是多么极端的情况,只需从 ThreadB 的循环中删除 notify
      由于您在 Thread 对象上进行同步,并且在 Thread 完成后实现会引发通知,因此代码仍然可以工作。
      这种行为违反直觉且容易出错。

      【讨论】:

        【解决方案4】:

        代码利用wait()机制确保result被其他ThreadB计算。

        要等待对象,您需要获取line 6,synchronized (b) 出现的对象的锁定。

        执行相同程序的更好方法是使用Thread#join() 方法。

        public final void join()
                    throws InterruptedException
        
        Waits for this thread to die.
        

        【讨论】:

          猜你喜欢
          • 2015-02-15
          • 2022-12-10
          • 2012-06-25
          • 2017-03-13
          • 1970-01-01
          • 1970-01-01
          • 2013-04-25
          • 2011-07-14
          相关资源
          最近更新 更多