线程崩溃

超扭矩

我有一个简单的项目,旨在更好地理解Java中的锁定和线程。本质上,我有一个缓存对象,该对象启动清理线程以删除超过给定期限的项目。测试类“ Tester”运行两个附加线程,一个用于添加要缓存的项目,另一个用于打印出缓存的内容。由于某些原因,当清理线程修改了嵌入在Cache中的HashMap时,它将停止任何进一步的迭代。我尝试同步访问器/更改器方法以及在Cache中围绕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;
    }
}
尼古拉斯·菲洛托(Nicolas Filotto)

考虑使用ConcurrentHashMapwhich是本机线程安全的映射实现,而不是的情况HashMap

您的错误主要是在这里:

public Collection<ObjectWrapper> getValues()
{
    synchronized(LOCK)
    {
        return cachedObjects.values();
    }
}

public Set<Object> getKeys()
{
    synchronized(LOCK)
    {
        return cachedObjects.keySet();
    }
}

仅共享HashMap非线程安全集合中实际提供的密钥和值,这样做是不够的,因此,当您遍历它们的内容时,您需要同步访问,或者可以简单地返回安全副本,如下所示:

public Collection<ObjectWrapper> getValues()
{
    synchronized(LOCK)
    {
        return new ArrayList<>(cachedObjects.values());
    }
}

public Set<Object> getKeys()
{
    synchronized(LOCK)
    {
        return new HashSet<>(cachedObjects.keySet());
    }
}

您还需要使ObjectWrapper线程安全,因为它是要共享的,否则您的代码将仍然不是线程安全的。最简单的方法是使其不可变,如下所示:

public class ObjectWrapper
{
    private final Object obj;
    private final long expireTime;

    public ObjectWrapper(Object obj, long expireTime)
    {
        this.obj = obj;
        this.expireTime = expireTime;
    }

    public Object getObj()
    {
        return obj;
    }

    public long getExpireTime()
    {
        return expireTime;
    }
}

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

JavaFX线程崩溃

来自分类Dev

删除线程时崩溃

来自分类Dev

删除线程时崩溃

来自分类Dev

JavaFX线程崩溃

来自分类Dev

如何使线程崩溃或故意将线程挂起?

来自分类Dev

简单的多线程程序崩溃?

来自分类Dev

Spyder在多线程后崩溃

来自分类Dev

OS X上的Unity崩溃:UnityGfxDeviceWorker线程崩溃

来自分类Dev

curl在线程调用中崩溃

来自分类Dev

在释放模式下提升线程崩溃

来自分类Dev

TStringList.IndexOf()导致线程崩溃

来自分类Dev

Android Looper线程因NullPointerException而崩溃

来自分类Dev

Perl Net :: SSH2与线程崩溃

来自分类Dev

pyQt和线程应用程序崩溃

来自分类Dev

LinkedList已修改,线程使程序崩溃

来自分类Dev

创建新实例会导致线程崩溃

来自分类Dev

如何使用多线程使系统崩溃

来自分类Dev

在Android中杀死/关闭线程时崩溃

来自分类Dev

Spritekit游戏崩溃(由于SKLightNode线程问题?)

来自分类Dev

Android:简单线程示例崩溃

来自分类Dev

在多个线程上访问 ViewContext 导致崩溃

来自分类Dev

为什么启动线程时表单崩溃?线程安全吗?

来自分类Dev

Tkinter python 在尝试登录主线程的新线程上崩溃

来自分类Dev

为什么此多线程程序可以工作(而不崩溃)?

来自分类Dev

如果不在主线程上,NSAttributedString initWithData和NSHTMLTextDocumentType崩溃

来自分类Dev

尝试在线程上打开相机时程序崩溃

来自分类Dev

设置多线程调试(/ MTd)(C ++)时发生崩溃

来自分类Dev

Handler.post()线程,正在崩溃的应用程序

来自分类Dev

尝试在线程中显示AlertDialog时,应用崩溃