Ich habe ein einfaches Projekt Ich arbeite daran, mein Verständnis von Sperren und Threading in Java zu verbessern. Im Wesentlichen habe ich ein Cache-Objekt, das einen Aufräum-Thread startet, um Elemente nach einem bestimmten Alter zu entfernen. Die Testklasse "Tester" führt zwei zusätzliche Threads aus, einen zum Hinzufügen von Elementen zum Zwischenspeichern und einen zum Ausdrucken des Cache-Inhalts. Wenn der Bereinigungs-Thread die in Cache eingebettete HashMap ändert, werden aus irgendeinem Grund keine weiteren Iterationen mehr ausgeführt. Ich habe versucht, die Accessor/Mutator-Methoden zu synchronisieren sowie um ein LOCK-Objekt im Cache zu synchronisieren. Irgendwelche Ideen oder Hilfe wären muy beueno. Betrachten)Thread Absturz
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;
}
}
Danke, ich war ein Verwenden Sie ConcurrentHashMap anstelle von HashMap. Ich bin nicht sicher, wie man ObjectWrapper unveränderlich macht, da es nur ein verschachteltes Objekt ist und direkt von anderen Threads geändert wird. Ich bin mir sicher, dass es nur meine Ignoranz ist. – supertorqued
in Multithreading-Env die Regel ist immer teilen thread-sichere Objekte so hier wie Sie Instanzen des Typs ObjectWrapper teilen, muss die Klasse threadsicher sein –