【问题标题】:Confusion in ReentrantLockReentrantLock 的困惑
【发布时间】:2015-07-29 21:25:18
【问题描述】:

我正在尝试了解 ReentrantLock 在 Java 中的内部工作原理。

我已经创建了一个示例:-

package com.thread.trylock;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class ReentrantLockingDemo {

    final Lock lock = new ReentrantLock();

    public static void main(final String... args) {

        new  ReentrantLockingDemo().go();

    }

    private void go() {

        Runnable run1 = newRunable();
        Thread t1 = new Thread(run1, "Thread1");
        System.out.println(run1.hashCode());
        t1.start();

        Runnable run2 = newRunable();
        Thread t2 = new Thread(run2, "Thread2");
        System.out.println(run2.hashCode());
        t2.start();

    }

    private Runnable newRunable() {

        return new Runnable() {

            @Override

            public int hashCode() {

                return super.hashCode();

            }

            @Override

            public void run() {

                do {

                    try {

                        if (lock.tryLock(500, TimeUnit.MILLISECONDS)) {

                            try {

                                System.out.println("locked thread "

                                        + Thread.currentThread().getName());


                                Thread.sleep(1000);


                            } finally {

                                lock.unlock();

                                System.out.println("unlocked locked thread "

                                        + Thread.currentThread().getName());

                            }

                            break;

                        } else {

                            System.out.println("unable to lock thread "

                                    + Thread.currentThread().getName()

                                    + " will re try again");

                        }

                    } catch (InterruptedException e) {

                        e.printStackTrace();

                    }

                } while (true);

            }     

        };

    }

}



//Output something like this (which may be slightly different on your machine)

locked thread Thread2

unable to lock thread Thread1 will re try again

locked thread Thread1

unlocked locked thread Thread2

unlocked locked thread Thread1

现在我的问题是有 2 个线程对象和 2 个可运行对象和 2 个线程。每个线程都应该在自己的堆栈帧上为不同的可运行对象运行 run 方法。如果每个线程使用不同的可运行对象在堆栈上运行自己的运行方法,则输出应该不同。

我见过一些例子,我们创建了几个线程,我们将一个共享对象传递给这些线程,我们在该共享对象的方法中进行锁定和解锁。这里的对象是不共享的。有 2 个可运行对象传递给 2 个线程对象,但可运行对象表现为共享对象。

您能否解释一下可能导致此输出的原因?或者可以提供一些澄清

谢谢

【问题讨论】:

    标签: java multithreading


    【解决方案1】:

    这里的对象是不共享的

    两个线程都在运行自己的 Runnable 实例是正确的,因此两个线程不共享一个公共 Runnable。

    但是两个 Runnable 实例都在使用封闭类的共享对象,这就是锁对象。所以他们在这个对象的帮助下相互同步。只要另一个线程通过调用持有锁,一个线程就会被阻塞

    lock.tryLock(500, TimeUnit.MILLISECONDS)
    

    为什么两个 Runnable 实例都可以访问被定义为类 ReentrantLockingDemo 的私有变量的锁对象,这里解释了 Anonyomous Classes

    所以当你写的时候

    private Runnable newRunable() {
    
        return new Runnable() {...};
    }
    

    你创建了一个继承自 Runnable 的匿名内部类的新实例,它可以访问外部类的所有 final(或在 Java 8 中也是所有有效的 final)字段。

    因此,即使您没有将共享对象显式传递给 Runnable 实例,它们也会使用共享对象进行同步,在本例中为锁定对象。

    【讨论】:

    • this 始终是最终的。
    • 这是正确的,但这是否与答案有关?
    • 这是对答案“Runnable 可以访问所有最终 ... 字段”的附加说明/澄清。 Runnable 捕获this,它始终是最终的。注意:如果它是一个 lambda,它将捕获 lock 而不是 this
    • @GoyalVicky 通常可以使用synchronized(object) 将线程与任何类型的对象同步,但是自从 Java 1.5 和 Lock 接口及其实现(这里是 ReentrantLock)的引入之后,它们是通常用于锁定,尤其是在您需要附加功能时。例如,您使用不会永远等待的tryLock。这对于普通的同步块是不可能的。
    • @Peter Ah 谢谢。你说得对,我忘了说。
    【解决方案2】:

    这里的对象是不共享的。

    Runnable 和 Threas 不共享。

    有两个对象是共享的ReentrantLockingDemo.thisReentrantLockingDemo.this.lock 这是锁的共享使这个工作。

    可运行对象表现为共享对象。

    您没有打印出 Runnable 的详细信息,因此您无法确定这一点。尝试在run() 中添加以下内容

    System.out.println(this);
    

    它应该打印带有不同 hashCode 的类名。

    在单个对象或多个对象(如上例中)同步的情况下,线程之间是否总是共享这个锁对象?

    锁对象没有什么特别之处,这意味着它必须是共享的。共享对象的原因是由于数据结构的布局方式。你有一个 ReentrantLockingDemo 实例,它有一个字段是 ReentrantLock 的一个实例。没有比这更复杂或更特别的了。

    虽然在不同的对象上使用它不会起到任何作用,因为实例变量也会变得线程安全,因为对象不同。

    唯一的different 对象是两个Runnable

    。在这种情况下,线程之间共享锁

    当两个线程使用同一个对象时。在这种情况下,只有其中一个,所以毫无疑问,它是共享的。

    你能提供以上链接吗?

    有时我们会想,因为一个问题很难掌握,所以它一定很复杂。事实上,它真的非常简单。

    您只创建一个锁,因此必须共享。

    【讨论】:

    • 是的,可运行对象有不同的哈希码值。 Reentrant Object 也会对实例化它的 Object 进行锁定。即 ReentrantLockingDemo 有一个 Reentrant 对象,所以它锁定 ReentrantLockingDemo 对象?是否等同于 synchronized(this)?
    • 您在该类的实例上定义的唯一锁,因此它是您唯一可以引用的锁。 synchronized(this) 不同,因为 this 没有改变。它类似于synchronized(lock)synchronized(ReeentrantLockingDemo.this)
    • 非常感谢您的解释
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-11-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多