在不同的监视器上使用同步块意味着什么?这个'实例?

时间:2015-05-10 15:46:45

标签: java multithreading

我有以下代码。它有两个对象,即 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();
            }
        }
    }

3 个答案:

答案 0 :(得分:5)

synchronized(this)表示如果另一个线程位于同一个this引用的对象上同步的代码块内,则无法输入此代码块。

synchronized(b)表示如果另一个线程位于同一个b引用的对象上同步的代码块内,则无法输入此代码块。

他们因此完全一样。唯一的区别是用于锁定的对象。

请注意,在Thread类型的对象上等待,同步和通知是一个非常糟糕的主意。它会混淆事物,并会导致不必要的行为,因为其他方法(例如join())也使用Thread作为监视器。

答案 1 :(得分:4)

把它想象成孩子的游戏,谁拥有[无论什么对象]可以说话。持有监视器对象的人可以用计算术语执行。

监视器是您要锁定的对象,在任何给定时间,只有一个线程访问每个监视器对象的同步块保护的代码。对象本身是任意的,并不会对同步有太大的影响(尽管你必须注意重新分配变量以及null引用)。此外,JB Nizet在Thread对象上进行同步时提出了一个很好的观点,因为许多内部VM方法可以做到这一点,你可以导致市场,很难发现错误和死锁。

进入不同同步块的两个线程锁定在不同的监视器上将同时执行 ,类似于两个独立的人群播放/制定“谁曾经持有xxx会说话”游戏。锁定this只是表示单个锁同步而不创建其他锁对象的便捷方式。

在您的情况下,ThreadB bthis类中指向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:请查看可能已在论坛中提出的类似问题。他们可能有助于提供额外的理解。