如何判断是否在 Java 中的同步块中?
How to tell if in a synchronised block in Java?
这一定有一个简单的答案,但我只是不知道它是什么...如果我说,在 Java 中执行以下操作:
class First{
public void first(){
Second second=new Second();
synchronized(this){
second.second(this);
}
second.second(this);
}
}
如何检查 Second.second
在调用此方法之前是否已获得同步锁,如果不是这种情况可能会抛出异常?例如:
class Second{
public void second(First first){
if(!/*want to test that lock obtained for first, but don't know how*/){
throw new RuntimeException("Must lock first!");
}
}
}
我希望第二次调用 Second.second
抛出 RuntimeException
如果上面的代码不明显。
有一个方法:)
public void second(First first) {
if (!Thread.holdsLock(first)) throw new IllegalStateException("Lock required");
}
然而,你不想要这个。
你要的是这个:
public void second(First first) {
synchronized (first) {
// do stuff
}
}
如果一个线程持有一个锁,然后您再次同步它,那是免费的,并且不会破坏任何东西:它不需要时间,也不会冻结您的线程。您可以 re-fetch 锁定您的线程已经持有的锁。 Java 维护一个计数器。 (锁是可重入的)。
要求调用者获得这个锁似乎很愚蠢;为什么不自己买呢?如果来电者已经获得它,没问题。时间紧迫,代码继续运行。
注意:就代码风格而言,抛出 RuntimeException 是不好的,在消息中放一个感叹号是非常糟糕的(想想看;异常中 90% 以上的消息都会以 ! 和结尾)查看日志真的很烦人)。我认为您也不需要像这样提前退出的大括号。因此,如果您必须使用 'check and throw' 样式,该代码段会为您应用一些修复程序:)
I want the second call to Second.second to throw the RuntimeException
if this is not obvious to the code above.
我认为这是个坏主意。您要么希望 First 处理锁而 second 不关心,要么 Second 处理锁,而不管它是 First 还是 Third。
如果我们将其与标准库中的 classes 进行比较,我们可能会查看 HashMap 与 ConcurrentMap。 HashMap 是 non-threadsafe class - 也就是说,它与示例中的 Second 相同。 ConcurrentMap 是“线程安全的”class - 也就是说,它处理自己的同步操作。
这实际上取决于什么构成“线程安全”,因此需要更多关于如何使用 class 的知识才能知道 thread-safety 的 ConcurrentMap 方法是否会实际提供 thread-safety .
除 First 之外,是否有其他人可以访问 Second 的同一个实例,而您正从这个角度防止 multi-threaded 访问?如果是这样,ConcurrentMap 方法可能更合适。在 multi-threaded 环境中,Second 本身是否会发生多个操作?如果是这样,手动锁定在First会更合适。
使用地图对 Second 进行多项操作的示例。
Map<Integer, String> map...
... // lets say map has 3 elements by this point and there are 2 threads running.
if (map.size() < 4)
{ // <--- thread may switch here, so both threads are inside the if block
map.put(map.size(), "This map is too small");
// Both threads have put in "This map is too small" to the map.
}
对于这个简单的snippet,无论map是HashMap还是ConcurrentMap,我们都无法避免“This map is too small”被添加两次。因此,尽管 ConcurrentMap 提供了“thread-safety”,但这段代码实际上并不是 thread-safe。因此,我们需要一个外部锁:
...
synchronized (map)
{
if (map.size() < 4)
{
map.add(map.size(), "This map is too small");
}
}
因此在这种情况下,ConcurrentMap 不会提供任何好处,使用更简单的 HashMap 将是正确的选择。
这一定有一个简单的答案,但我只是不知道它是什么...如果我说,在 Java 中执行以下操作:
class First{
public void first(){
Second second=new Second();
synchronized(this){
second.second(this);
}
second.second(this);
}
}
如何检查 Second.second
在调用此方法之前是否已获得同步锁,如果不是这种情况可能会抛出异常?例如:
class Second{
public void second(First first){
if(!/*want to test that lock obtained for first, but don't know how*/){
throw new RuntimeException("Must lock first!");
}
}
}
我希望第二次调用 Second.second
抛出 RuntimeException
如果上面的代码不明显。
有一个方法:)
public void second(First first) {
if (!Thread.holdsLock(first)) throw new IllegalStateException("Lock required");
}
然而,你不想要这个。
你要的是这个:
public void second(First first) {
synchronized (first) {
// do stuff
}
}
如果一个线程持有一个锁,然后您再次同步它,那是免费的,并且不会破坏任何东西:它不需要时间,也不会冻结您的线程。您可以 re-fetch 锁定您的线程已经持有的锁。 Java 维护一个计数器。 (锁是可重入的)。
要求调用者获得这个锁似乎很愚蠢;为什么不自己买呢?如果来电者已经获得它,没问题。时间紧迫,代码继续运行。
注意:就代码风格而言,抛出 RuntimeException 是不好的,在消息中放一个感叹号是非常糟糕的(想想看;异常中 90% 以上的消息都会以 ! 和结尾)查看日志真的很烦人)。我认为您也不需要像这样提前退出的大括号。因此,如果您必须使用 'check and throw' 样式,该代码段会为您应用一些修复程序:)
I want the second call to Second.second to throw the RuntimeException if this is not obvious to the code above.
我认为这是个坏主意。您要么希望 First 处理锁而 second 不关心,要么 Second 处理锁,而不管它是 First 还是 Third。
如果我们将其与标准库中的 classes 进行比较,我们可能会查看 HashMap 与 ConcurrentMap。 HashMap 是 non-threadsafe class - 也就是说,它与示例中的 Second 相同。 ConcurrentMap 是“线程安全的”class - 也就是说,它处理自己的同步操作。
这实际上取决于什么构成“线程安全”,因此需要更多关于如何使用 class 的知识才能知道 thread-safety 的 ConcurrentMap 方法是否会实际提供 thread-safety .
除 First 之外,是否有其他人可以访问 Second 的同一个实例,而您正从这个角度防止 multi-threaded 访问?如果是这样,ConcurrentMap 方法可能更合适。在 multi-threaded 环境中,Second 本身是否会发生多个操作?如果是这样,手动锁定在First会更合适。
使用地图对 Second 进行多项操作的示例。
Map<Integer, String> map...
... // lets say map has 3 elements by this point and there are 2 threads running.
if (map.size() < 4)
{ // <--- thread may switch here, so both threads are inside the if block
map.put(map.size(), "This map is too small");
// Both threads have put in "This map is too small" to the map.
}
对于这个简单的snippet,无论map是HashMap还是ConcurrentMap,我们都无法避免“This map is too small”被添加两次。因此,尽管 ConcurrentMap 提供了“thread-safety”,但这段代码实际上并不是 thread-safe。因此,我们需要一个外部锁:
...
synchronized (map)
{
if (map.size() < 4)
{
map.add(map.size(), "This map is too small");
}
}
因此在这种情况下,ConcurrentMap 不会提供任何好处,使用更简单的 HashMap 将是正确的选择。