8

ReentrantLock#tryLock(long,TimeUnit) 实现在尝试获取锁时在做什么?假设线程 A 确实拥有锁myLock,线程 B 调用myLock.tryLock(10,SECONDS),线程 B 是在休眠还是在等待?

换句话说,是这两种实现的区别:

1.

while (true)
   try {
     if (readLock.tryLock())
       return;
     MILLISECONDS.sleep(5);
   }catch (InterruptedException e) {}

2.

 while (true)
   try {
     if (readLock.tryLock(5,MILLISECONDS))
       return;
   }catch (InterruptedException e) {}
4

5 回答 5

3

首先,如果锁被释放,第二个将等待少于 5 毫秒,因为它不需要等待从sleep. 因此,它较少受到饥饿问题的影响。

然后,j.u.c.l包使用 LockSupport#park 方法来暂停线程,而不是Thread.sleep. 据我了解,它对线程调度程序有影响,park允许更低的延迟,但不确定它sleep是如何实现的。

另外,你的代码没有任何意义,通过lock()方法可以达到完全相同的效果。

于 2011-12-06T10:42:19.830 回答
1

从技术上讲,等待线程的状态没有区别。来自 JavaDoc:

如果锁被另一个线程持有,则当前线程将被禁用以用于线程调度目的并处于休眠状态 [...]

这与睡眠时发生的情况非常相似,但我想除非我们知道实现,否则我们不能肯定地说。

现在,请注意这部分:

[...] 处于休眠状态,直到发生以下三种情况之一: 锁被当前线程获取;或者 [...]

这意味着如果锁在此期间空闲,它将获取并返回。在另一种情况下,当它处于睡眠状态时,即使它是空闲的,线程也没有机会获得锁。

这两种情况之间可能出现的另一个细微差别是,定时 trylock 对 ReentrantLock 的公平策略很敏感。那是:

如果此锁已设置为使用公平排序策略,则如果任何其他线程正在等待该锁,则不会获取可用锁。

众所周知,不定时的 trylock 是不公平的,即使其他线程已经在等待它,它也可能成功获取锁。

于 2011-12-06T10:42:37.537 回答
1

它正在等待锁定并且线程处于睡眠状态。

在内部,如果该tryLock(long, TimeUnit)方法未能立即获取锁,它会等待指定的时间量。如果锁在此时间之前可用,它会立即返回锁。请注意,在这种情况下,当有多个线程请求锁时,ReentrantLock将随机选择一个线程将锁交给下一个。true可以通过在构造函数中传递公平值来更改此行为new ReentrantLock(true)

第二个示例将仅每五毫秒检查一次锁。如果锁在休眠时可用,并且在唤醒之前被分配给另一个线程,则该线程将无法获取锁。

如果您在使用此代码时有许多线程在等待锁定,请注意,您提供的任何一种解决方案都不能保证每个线程都会在某个时候获得锁定。在五毫秒结束之前,第二个代码可以继续被另一个线程狙击。第一个代码是随机的,但即使设置了公平值,每个线程也会每五毫秒放弃一次排队。如果是这种情况,您最好增加超时值。一个好的值大约是您期望每个线程转一圈所花费的最大时间的两倍。

于 2011-12-06T10:44:56.097 回答
0

我猜第二个将等待 5 毫秒来获得与第一个不同的锁定,后者将立即尝试锁定。所以线程 B 将等待,如果在 5 毫秒(5 毫秒内)锁定它没有获得锁定它会返回 false。通常,如果您的超时时间为 5 毫秒,则没有区别,但如果您增加此数字,您将获得清晰的图像。

5ms 是超时,它将等待 5ms 锁定,这意味着如果锁定在 3ms 后可用,它将在 3ms 后返回 true。

于 2011-12-06T10:36:29.773 回答
0

有关如何实现锁和其他并发原语的重要参考,请参阅 Shavit 和 Herlihy 的出色的多处理器编程艺术

于 2011-12-06T20:03:34.050 回答