第二个线程如何检查并重新检查第一个线程当前使用的类的锁定对象?

时间:2017-02-09 14:19:48

标签: java multithreading synchronization thread-safety

我对java中的synchronized方法的理解,其中第一个线程获取了锁对象,因此如果第二个线程检查它,它会看到它正在使用中,并且"等待"直到线程1完成,然后锁定被传回,而第二个线程可以获取锁定并继续。只是学习如果那个off / over简化......这就是原因。

我的问题是第二个线程的内部机制是什么"等待" ...它是否会继续轮询或重新检查锁定,直到它看到它的空闲状态?如果是这种情况会影响一堆线程而不是第一个/第二个例子吗?或者更像是一种注册类型的机制,它允许将第二个线程放入一个排序队列中,然后在锁定可用后得到通知?

好奇。谢谢!

2 个答案:

答案 0 :(得分:1)

JVM处理内部锁定的方式因地点而异,诸如JVM供应商,服务器/客户端选项,活动线程,等待时间,队列大小等因素......在锁定时考虑了线程行为。

特别是HotSpot JDK VM的实现对于像我这样的普通外行来说将是非常神秘的,我将把它留在这里进行进一步调查:http://hg.openjdk.java.net/jdk8u/jdk8u60/hotspot/file/37240c1019fd/src/share/vm/runtime/synchronizer.cpp

如果不深入了解源代码,AFAIK内部锁定会保留一组不拥有锁的等待线程。如果线程尝试获取并失败,则会将其添加到此集合中,并可能执行一些不同的操作:

  1. Spin,这里可以使用很多算法。当旋转成功获取锁定时,将通知第二个线程。
  2. 上下文切换,暂停线程并释放处理器。退出线程会通知下一位服务员。
  3. 睡眠,暂停线程但保留处理器。与2相同。
  4. 线程将执行的操作通常由启发式或线程正在获取的任何类型的锁定来确定。系统还可以将不同的方法组合在一起,例如在睡觉前旋转N次,然后进行上下文切换。这取决于系统。关于我所提出的一些或所有要点,我可能错了,因为我找不到任何支持我所说的内容。

    老实说,锁定的内部实现对Java开发人员来说应该很少。 JVM的线程调度和锁定非常高效,使用这些算法的工程师非常聪明,需要花费数周,数月和数年的时间进行测试,并确保实现提供最佳性能。这就是为什么最低级别的线程控制来自thread parking,你需要JNI或其他语言。如果您要实现自己的同步器,请考虑使用AbstractQueuedSynchronizerJDK source经过精心记录,您将看到非内在锁和其他高级同步器(如ReentrantLock)的工作原理。

    修改

    JVM实现路径如下:

    1. 运行/ synchronizer.cpp
    2. High level spin
    3. Call to park event
    4. 操作系统调用:
    5. 仅限Linux:NPTL - > Futex syscall

答案 1 :(得分:1)

  

我的问题是第二个线程的内部机制是什么?等待" ...是否继续轮询或重新检查锁定,直到它看到它的空闲状态?

在大多数情况下,这根本不是由JVM处理,而是由OS中的线程层处理。也就是说,线程肯定不是轮询。当第二个线程遇到已经锁定的锁时,它会停止运行并被放入与该锁相关联的有序等待队列中。锁解锁后,等待队列中的第一个线程(如果有)将被唤醒并移入运行队列。

  

如果是这种情况会影响一堆线程而不是第一个/第二个例子吗?

没有。队列可以很好地扩展到大量的线程。

  

或者它更像是一种注册类型的机制,允许将第二个线程放入排序队列中,然后在锁定可用后得到通知?

右。线程完全停止运行,解锁锁的线程是启动线程再次运行的线程(或某种类型的主管线程)。