synchronized—如何判断是否在java中的同步块中?

wmtdaxz3  于 2021-07-06  发布在  Java
关注(0)|答案(2)|浏览(268)

这一定有一个简单的答案,但我只是不知道它是什么。。。如果我在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 如果这对上面的代码不明显。

um6iljoc

um6iljoc1#

有一种方法:)

public void second(First first) {
    if (!Thread.holdsLock(first)) throw new IllegalStateException("Lock required");
}

但是,你不想这样。
你想要的是:

public void second(First first) {
    synchronized (first) {
        // do stuff
    }
}

如果一个线程持有一个锁,然后你再次同步它,这是免费的,而且不会破坏任何东西:它不需要时间,也不会冻结你的线程。您可以重新获取线程已经持有的锁。java维护一个计数器(锁是可重入的)。
要求调用者获得这个锁似乎很愚蠢;为什么不自己去弄呢?如果调用者已经获得了它,没问题。不浪费时间,代码继续工作。
注意:就代码风格而言,抛出runtimeexception是不好的,而在消息中加一个感叹号是非常不好的(想想看;异常中90%以上的消息会以错误结尾!查看日志会变得很烦人)。我认为你也不需要像这样提前离开。因此,如果您必须使用“check-and-throw”样式,那么编写代码段时会为您应用一些修复:)

yyyllmsg

yyyllmsg2#

我希望第二次调用second.second时抛出runtimeexception,如果这对上面的代码不明显的话。
我认为这是个坏主意。要么你想第一个处理锁,第二个不关心,要么第二个处理锁,不管它是第一个还是第三个。
如果我们将它与标准库中的类进行比较,我们可能会看到hashmap与concurrentmap。hashmap是一个非线程安全类——也就是说,它与示例中的second相同。concurrentmap是一个“线程安全”类,也就是说,它处理自己的同步操作。
这实际上取决于“threadsafe”的构成,因此需要更多关于如何使用类的知识,以了解线程安全的concurrentmap方法是否真正提供线程安全。
除了first之外,是否还有其他人可以访问second的同一个示例,并且您正从这个Angular 防范多线程访问?如果是这样,concurrentmap方法可能更合适。在多线程环境中,second本身是否发生多个操作?如果是这样,首先手动锁定会更合适。
第二个使用map的多个操作的例子。

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.
}

对于这个简单的代码段,无论Map是hashmap还是concurrentmap,我们都不能防止“thismap is too small”被添加两次。因此,尽管concurrentmap提供了“线程安全”,但这段代码实际上并不是线程安全的。因此,我们需要一个外部锁:

...
synchronized (map)
{
   if (map.size() < 4)
   {
      map.add(map.size(), "This map is too small");
   }
}

因此,在这种情况下,concurrentmap不会提供任何好处,使用更简单的hashmap将是正确的选择。

相关问题