以下同步块的目的是什么?

时间:2012-09-15 06:41:21

标签: java synchronization opencms

我遇到OpenCMS的稳定性问题。当我进行线程转储时,许多线程(400)正在等待以下代码中的synchronized (m_processingFiles)块:

public class CmsJspLoader ... {
...

private static Set m_processingFiles = Collections.synchronizedSet(new HashSet());

...
...
...
public String updateJsp(...) {
....

while (m_processingFiles.contains(jspVfsName)) {
    // wait a little bit until the first thread finishes
    try {
        synchronized (m_processingFiles) {
            m_processingFiles.wait(100);
        }
    } catch (InterruptedException e) {
        // ignore
    }
}
...
}
...
}

代码是OpenCMS的一部分。 代码中没有notify()。在显示的sync块中没有 state 或读取共享变量的更改。 但是,有400个线程在等待它,这意味着,只是要通过这个sync,最后一个应该等待40秒!!!

我根本就不明白它的目的。有什么我没看到的吗?

2 个答案:

答案 0 :(得分:2)

如果没有notify或notifyAll调用,这将基本上像100ms睡眠一样。在100ms之后,线程将唤醒并继续。假设在同步块内只有等待,那么这只是一种奇怪的睡眠方式。同步块触发memory barrier可能会导致其他一些影响。所以可能会出现一些微妙的线程安全问题。

在解释线程转储时要注意的一件事是400个线程是否被阻塞等待进入同步块或等待等待?当线程进入等待时,它基本上从同步块释放锁,以便另一个线程可以输入它。当线程从等待中醒来时,将重新获取锁定。

如果线程转储说“等待监视器条目”,则一个线程在同步块中,而其他所有线程都试图进入。这表明你在这里遇到了一个主要的并发问题。

但是,如果线程转储显示类似“在Object.wait()”中的内容,则表示线程处于100ms等待状态,其他线程可以自由进入同步块。在这种情况下,这意味着循环条件仍然是假的,所以看看那边发生了什么,而不是等待线程发生了什么。

也就是说,如果可以执行notify / notifyAll,那么无论进程的另一端是什么,它都会减少延迟和唤醒成本并检查线程是否仍然处于休眠状态。

答案 1 :(得分:2)

必须在代码中的某个位置,其中线程将jspVfsName添加到m_processingFiles,执行更多操作,然后从{{jspVfsName移除m_processingFiles 1}}。如果不是这种情况,那么你的其他线程只会在wait()循环中永远while。出于某种原因,实现者不希望任何其他线程在执行其他处理时执行updateJsp

我建议您检查一下代码,看看jspVfsName实际上是什么,然后找到可以在m_processingFiles中添加/删除代码的位置。也许那时你也会理解为什么当updateJspjspVfsName时,作者不希望m_processingFiles运行。

找到后,您可以检查“其他”代码,看看jspVfsName是否可以添加到m_processingFiles从未删除。如果是这样,那会(自然地)引起活锁,这可以解释你的稳定性问题。

或者可能是updateJsp被频繁调用,并且修改m_processingFiles的“其他”代码也被频繁调用,以至于它导致了一个主要的并发瓶颈?您的应用程序是否有问题导致updateJsp被调用的频率超过应有的频率(可能是在每个请求上,而不是每次在服务器上放置新的JSP文件时)?

如果updateJsp非常频繁地运行,但这不是由您的应用程序问题引起的,您可以尝试简单地缩短wait()期。这不应该伤害任何东西 - 它只会让等待的线程检查jspVfsName是否仍然在m_processingFiles更频繁。在CPU条件下,100ms是 长, 时间!

相关问题