java - 在与 'this' 实例不同的监视器上有一个同步块(synchronized block)是什么意思?

标签 java multithreading

我有以下一段代码。它有两个对象,即 MultiThreadingTestThreadB 对象。当我们说synchronized(b)时,它到底是什么意思? “主”线程能否在 ThreadB 完成执行之前锁定 b?我无法理解同步块(synchronized block)中监视对象的意义。

 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();
            }
        }
    }

最佳答案

把它想象成 child 的游戏,谁拿着 [whatever object] 就可以发言。谁持有监视器对象,谁就可以执行计算。

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

进入锁定在不同监视器上的不同同步块(synchronized block)的两个线程将并发执行,类似于两组不同的人玩/执行“谁持有 xxx 就可以发言”游戏。锁定 this 只是一种无需创建额外的锁对象即可显示单个锁同步的便捷方式。

在您的情况下,ThreadB b 是从 ThreadB 类中指向的与 this 相同的对象,这意味着只有一个线程可以进入您定义的任何同步块(synchronized block)一次。该顺序高度依赖于哪个线程先运行、线程调度程序甚至底层系统。

监控对象的主要原因是为了实现复杂的线程安全机制。想象一个系统,其中每个同步块(synchronized block)都是单线程访问(即在任何时候,任何线程进入同步块(synchronized block)都会阻止整个 VM 中试图进入同步块(synchronized block)的所有其他线程)这不仅会导致性能大幅下降,还会只是没有意义。如果两个不相关的应用程序模块不共享数据且从不交互,为什么它们应该相互锁定?

当然,解决方案是让一个模块使用一个(或多个)监视器对象,这些对象与另一个模块不相关/不关联,因此两个模块可以彼此独立地同时执行(假设这是所需的行为)。

为了进一步说明,您可以这样写:

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() 和其他方法的冲突)。

关于java - 在与 'this' 实例不同的监视器上有一个同步块(synchronized block)是什么意思?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30153362/

相关文章:

c# - 不使用 ThreadPool 的 C# 中的周期性任务

multithreading - 异步任务超时?

java - 重新启动 aerospike 服务器读取旧值

java - 如何使用 jcreator 制作复制粘贴脚本?

java - 内部类太多?

java - 在 Java 中使用 10 个线程打印 1 到 100

java - 将单元格限制为 Apache POI 中的数值

java - 如何在不使用 API 的情况下将八进制转换为不同形式的十进制?

java - Java 线程中的 ObjectInputStream 失败

C# 线程 : Console application in new thread is invisible