我有一个webapp,我正在进行一些负载/性能测试,特别是在我们希望有几百个用户访问同一页面并在此页面上每10秒点击一次刷新的功能.我们发现我们可以使用此功能进行改进的一个方面是在一段时间内缓存来自Web服务的响应,因为数据没有变化.
在实现这个基本缓存之后,在一些进一步的测试中,我发现我没有考虑并发线程如何同时访问Cache.我发现在大约100毫秒内,大约有50个线程试图从缓存中获取对象,发现它已经过期,命中Web服务以获取数据,然后将对象放回缓存中.
原始代码看起来像这样:
private SomeData[] getSomeDataByEmail(WebServiceInterface service, String email) {
final String key = "Data-" + email;
SomeData[] data = (SomeData[]) StaticCache.get(key);
if (data == null) {
data = service.getSomeDataForEmail(email);
StaticCache.set(key, data, CACHE_TIME);
}
else {
logger.debug("getSomeDataForEmail: using cached object");
}
return data;
}
Run Code Online (Sandbox Code Playgroud)
因此,为了确保在对象key过期时只有一个线程正在调用Web服务,我认为我需要同步Cache get/set操作,并且似乎使用缓存键是一个很好的候选对象同步(这样,对电子邮件b@b.com的此方法的调用不会被方法调用a@a.com阻止).
我将方法更新为如下所示:
private SomeData[] getSomeDataByEmail(WebServiceInterface service, String email) {
SomeData[] data = null;
final String key = "Data-" + email;
synchronized(key) {
data =(SomeData[]) StaticCache.get(key);
if (data == null) {
data = service.getSomeDataForEmail(email); …Run Code Online (Sandbox Code Playgroud) java multithreading synchronization synchronized thread-safety
如果我使用String.intern()来提高性能,因为我可以使用"=="来比较实习字符串,我会遇到垃圾收集问题吗?实习字符串的垃圾收集机制与普通字符串有何不同?
在探索了java的字符串内部结构后,我对所谓的"烫发空间"感到困惑.我最初的理解是它保留了String 文字以及类元数据,如本问题所述.
我还阅读了有关该String.intern()方法的内容,并将其String放入String Pool中,返回对它的唯一实例的引用.我的理解是,这是与JVM的perm空间中存在的字符串文字相同的字符串池.对我来说,"烫发空间"可以修改是不可能的(毕竟它是永久性的,是吗?).但后来我发现这个问题,EJP对接受的答案的最高投票评论解释了这一点
现在,实习生的字符串已经可以用GC了.
暗示GC在perm空间上运行,这似乎不是永久性的.这如何调和?GC是否检查了烫发空间中的所有内容?GC是否检查字符串池中的所有内容,包括源中的字符串文字?内联字符串是否有第二个字符串池?GC是否只知道在收集时查看实习生的字符串?或者这个评论是错误的并且实际上是一个字符串阻止它成为GC'd(我希望不是这种情况)?