나는 간단한 프로젝트를 가지고 있는데, 나는 자바 로킹과 스레딩에 대한 나의 이해를 돕기 위해 노력하고있다. 기본적으로 주어진 나이를 지나서 항목을 제거하는 정리 스레드를 시작하는 캐시 개체가 있습니다. 테스트 클래스 "Tester"는 캐시에 항목을 추가하고 캐시 내용을 출력하는 두 개의 추가 스레드를 실행합니다. 캐시에서 임베드 된 HashMap을 정리 스레드가 수정할 때 어떤 이유로 더 이상 반복을 중지합니다. 접근 자/변이 자 메서드를 동기화하고 캐시의 LOCK 개체를 동기화하려고 시도했습니다. 어떤 아이디어 나 도움이 muy beueno가 될 것입니다.)스레드 크래킹
public class Cache
{
private HashMap<Object, ObjectWrapper> cachedObjects = new HashMap<>();
private static Cache cache = null;
private static int TIME_TO_KEEP = 60000; // 60 seconds
private final static Object LOCK = new Object();
public static Cache getInstance()
{
if (cache == null)
{
cache = new Cache();
}
return cache;
}
private Cache()
{
ScheduledExecutorService executor = Executors.newScheduledThreadPool(2);
Runnable task =() -> {
synchronized(LOCK)
{
System.out.println("Cleanup");
Set<Object> keys = cachedObjects.keySet();
final long now = System.currentTimeMillis();
keys.forEach(k -> {
try
{
{
ObjectWrapper ow = cachedObjects.get(k);
if(ow.getExpireTime() < now)
{
int size = cachedObjects.size();
cachedObjects.remove(k, ow);
System.out.println("DEL:" + k + ", from " + size + " to " + cachedObjects.size());
}
}
}
catch (Throwable t)
{
t.printStackTrace();
}
});
}
};
executor.scheduleWithFixedDelay(task, 5, 15, TimeUnit.SECONDS);
}
public void addObject(Object key, Object obj)
{
synchronized(LOCK)
{
ObjectWrapper ow = new ObjectWrapper(obj, System.currentTimeMillis() + TIME_TO_KEEP);
cachedObjects.put(key, ow);
}
}
public ObjectWrapper getObj(Object key)
{
synchronized(LOCK)
{
return cachedObjects.get(key);
}
}
public Collection<ObjectWrapper> getValues()
{
synchronized(LOCK)
{
return cachedObjects.values();
}
}
public Set<Object> getKeys()
{
synchronized(LOCK)
{
return cachedObjects.keySet();
}
}
public static void main(String[] args)
{
Cache cache = Cache.getInstance();
}
}
import java.util.*;
import java.util.concurrent.*;
public class Tester
{
private static Integer id = 0;
private static Cache cache = Cache.getInstance();
public static void main(String[] args)
{
ScheduledExecutorService executor = Executors.newScheduledThreadPool(2);
Runnable adder =() -> {
System.out.println("Adding id:" + ++id);
Object o = new Object();
cache.addObject(id, o);
};
executor.scheduleWithFixedDelay(adder, 5, 10, TimeUnit.SECONDS);
Runnable tester =() -> {
long currTime = System.currentTimeMillis();
System.out.println("Test: ");
Set<Object> keys = cache.getKeys();
keys.forEach(k -> {
ObjectWrapper o = cache.getObj(k);
System.out.println(k + ">" + currTime + "::" + o.getExpireTime());
});
};
executor.scheduleWithFixedDelay(tester, 20, 10, TimeUnit.SECONDS);
}
}
public class ObjectWrapper
{
private Object obj;
private long expireTime;
public ObjectWrapper(Object obj, long expireTime)
{
this.obj = obj;
this.expireTime = expireTime;
}
public Object getObj()
{
return obj;
}
public void setObj(Object obj)
{
this.obj = obj;
}
public long getExpireTime()
{
return expireTime;
}
public void setExpireTime(long expireTime)
{
this.expireTime = expireTime;
}
}
감사합니다. HashMap 대신 ConcurrentHashMap을 사용하여 작업을 수행 할 수 있습니다. ObjectWrapper를 단지 중첩 된 객체이고 다른 스레드에 의해 직접 변경되는 것처럼 어떻게 불변으로 만들지 모르겠습니다. 나는 그것이 단지 나의 무지라고 확신한다. – supertorqued
멀티 스레딩 env에서 규칙은 항상 스레드 안전 객체를 공유하므로 ObjectWrapper 유형의 인스턴스를 공유 할 때 클래스는 스레드 안전해야합니다. –