我写了一个名为AbcServlet.java
的Servlet,我有一个Static String field called cacheSeller
。它正在servlet的init
和 doGet
方法中填充。它由CacheSellerClearThread.java
清除,如下所示:
AbcServlet.java
public class AbcServlet extends HttpServlet {
private static String cacheSeller = null;
@Override
public void init() throws ServletException {
super.init();
cacheSeller = populateCacheSeller();
}
/**
* As soon as multiple requests are coming doGet is being called
*/
@Override
public void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
synchronized (this.getClass()) {
if (cacheSeller == null) {
cacheSeller = populateCacheSeller();
}
}
}
private String populateCacheSeller() {
String fetchItFromSomewhere = "";// some logic to fetch the sting
return fetchItFromSomewhere;
}
public static synchronized void clearCacheSeller() {
cacheSeller = null;
}
}
CacheSellerClearThread.java
/**
* This thread is clearing the string field cacheSeller of AbcServlet
*
*/
public class CacheSellerClearThread extends Thread {
public void run() {
while (true) {
try {
Thread.sleep(2000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
//Here it is clearing the static string field cacheSeller of AbcServlet
AbcServlet.clearCacheSeller();
}
}
}
如果查看代码,则在doGet方法中读取和修改cacheSeller值。所有请求线程都将执行doGet,同时CacheSellerClearThread将在每2秒后清除其值。所以为了保持cacheSeller值的数据完整性,我使用同步。
我需要一个建议,即如果没有在clearCacheSeller方法中使用显式同步并且在Servlet中没有应用显式类级别锁定,是否有任何其他方法可以实现此目的。 (我的意思是说使用任何高级并发API,如原子引用或您可以建议的任何其他API。)
我已经使用AtomicReference编写了新的实现,请建议,我是否需要在任何地方使用同步。
public class AbcServlet extends HttpServlet {
private static AtomicReference<String> cacheSeller = new AtomicReference<String>();
@Override
public void init() throws ServletException {
super.init();
cacheSeller.set(populateCacheSeller());
}
/**
* As soon as multiple requests are coming doGet is being called
*/
@Override
public void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
if (cacheSeller.get() == null) {
cacheSeller.compareAndSet(null, populateCacheSeller());
}
resp.getWriter().print(cacheSeller.get());
}
private String populateCacheSeller() {
String fetchItFromSomewhere = "";// some logic to fetch the sting
return fetchItFromSomewhere;
}
public static void clearCacheSeller() {
cacheSeller.set(null);
}
}
答案 0 :(得分:2)
我建议使用Executors
框架。
Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
AbcServlet.clearCacheSeller();
}
}, 2L,2L,TimeUnit.SECONDS);
在您的doGet
中,仅同步初始化:
@Override
public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String localCacheSeller = cacheSeller;
if (cacheSeller == null) {
synchronized (this.getClass()) {
if (cacheSeller == null) { //need this because cacheSeller may already have been initialized while we waited
cacheSeller = populateCacheSeller();
localCacheSeller = cacheSeller; //because the executor may clear it after we initialized
}
}
}
}
答案 1 :(得分:0)
您可以使用Google Guava之类的内容来创建缓存。
例如:
LoadingCache<String, String> cache =
CacheBuilder.newBuilder()
.expireAfterWrite(2, TimeUnit.MINUTES)
.build(loader);
有了这样的东西,你可以避免你的辅助线程清除缓存。
这个实现是一个简单的内存缓存,它也是线程安全的。
此致