我有以下代码。它有两个对象,即 MultiThreadingTest 和 ThreadB 对象。当我们说 synchronized(b)时,它到底意味着什么?可以'主要'线程在完成它的执行之前获取b的锁定?我无法理解同步块中监视对象的重要性。
package threads;
class MultiThreadingTest
{
public static void main(String[] args)
{
ThreadB b = new ThreadB();
b.setName("Thread B");
b.start();
synchronized(b)
{
System.out.println("Current thread : "+ Thread.currentThread().getName());
try
{
System.out.println("Waiting for b to complete...");
b.wait();
}
catch (InterruptedException e)
{
e.printStackTrace();
}
System.out.println("Total = "+b.total );
}
}
}
class ThreadB extends Thread
{
int total;
public void run()
{
synchronized(this)
{
System.out.println("Current thread : "+Thread.currentThread().getName());
for(int i=0;i<100;i++)
{
total = total + i;
}
notify();
}
}
}
答案 0 :(得分:5)
synchronized(this)
表示如果另一个线程位于同一个this
引用的对象上同步的代码块内,则无法输入此代码块。
synchronized(b)
表示如果另一个线程位于同一个b
引用的对象上同步的代码块内,则无法输入此代码块。
他们因此完全一样。唯一的区别是用于锁定的对象。
请注意,在Thread类型的对象上等待,同步和通知是一个非常糟糕的主意。它会混淆事物,并会导致不必要的行为,因为其他方法(例如join())也使用Thread作为监视器。
答案 1 :(得分:4)
把它想象成孩子的游戏,谁拥有[无论什么对象]可以说话。持有监视器对象的人可以用计算术语执行。
监视器是您要锁定的对象,在任何给定时间,只有一个线程访问每个监视器对象的同步块保护的代码。对象本身是任意的,并不会对同步有太大的影响(尽管你必须注意重新分配变量以及null
引用)。此外,JB Nizet在Thread
对象上进行同步时提出了一个很好的观点,因为许多内部VM方法可以做到这一点,你可以导致市场,很难发现错误和死锁。
进入不同同步块的两个线程锁定在不同的监视器上将同时执行 ,类似于两个独立的人群播放/制定“谁曾经持有xxx会说话”游戏。锁定this
只是表示单个锁同步而不创建其他锁对象的便捷方式。
在您的情况下,ThreadB b
是this
类中指向ThreadB
的同一对象,这意味着只有一个线程可以同时输入任何已定义的同步块。该顺序高度依赖于首先运行的线程,线程调度程序甚至底层系统。
监视对象的主要原因是可以实现复杂的线程安全机制。想象一个系统,其中每个同步块都是单线程访问(即在任何时候,任何线程进入同步块将保持整个VM中的每个其他线程试图进入同步块)不仅会导致大量性能下降,它只是没有意义。如果两个不相关的应用程序模块没有共享数据且从不进行交互,为什么要相互锁定?
当然,解决方案是让一个模块使用与另一个模块无关/不关联的一个(或几个)监视器对象,因此两者可以彼此独立地执行(假设这是所需的行为)。
为了进一步澄清,你可以写:
class MultiThreadingTest{
public static void main(String[] args){
ThreadB b = new ThreadB();
b.setName("Thread B");
b.start();
synchronized(b.lock){
System.out.println("Current thread : "+ Thread.currentThread().getName());
try{
System.out.println("Waiting for b to complete...");
b.lock.wait();
}catch(InterruptedException e){
e.printStackTrace();
}
System.out.println("Total = " + b.total );
}
}
}
class ThreadB extends Thread{
public final Object lock = new Object();
int total;
public void run(){
synchronized(lock){
System.out.println("Current thread : "+Thread.currentThread().getName());
for(int i = 0; i < 100; i++){
total = total + i;
}
lock.notify();
}
}
}
与完全效果与您使用的代码相同(更好,因为它解决了与Thread.join()和其他方法的冲突。)
答案 2 :(得分:0)
根据我的理解,没有。这个&#39;这个&#39; run()方法中的对象和&#39; b&#39; main()方法中的对象是相同的。
因此,主要的&#39;是不可能的。线程获取锁,直到线程完成执行。
在这种情况下,run()方法中的notify()似乎也是多余的,因为它在方法结束时,监视器上的锁将放弃任何方式。
PS:请查看可能已在论坛中提出的类似问题。他们可能有助于提供额外的理解。