Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/372.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 线程崩溃_Java_Multithreading - Fatal编程技术网

Java 线程崩溃

Java 线程崩溃,java,multithreading,Java,Multithreading,我有一个简单的项目,我正在努力更好地理解Java中的锁定和线程。实际上,我有一个缓存对象,它启动一个清理线程来删除超过给定时间的项。测试类“Tester”运行另外两个线程,一个用于向缓存添加项目,另一个用于打印缓存的内容。出于某种原因,当清理线程修改缓存中嵌入的HashMap时,它会停止任何进一步的迭代。我尝试了同步访问器/变异器方法,以及围绕缓存中的锁对象进行同步。任何想法或帮助都将由梅贝诺提供 公共类缓存 { private HashMap cachedObjects=new HashMap

我有一个简单的项目,我正在努力更好地理解Java中的锁定和线程。实际上,我有一个缓存对象,它启动一个清理线程来删除超过给定时间的项。测试类“Tester”运行另外两个线程,一个用于向缓存添加项目,另一个用于打印缓存的内容。出于某种原因,当清理线程修改缓存中嵌入的HashMap时,它会停止任何进一步的迭代。我尝试了同步访问器/变异器方法,以及围绕缓存中的锁对象进行同步。任何想法或帮助都将由梅贝诺提供

公共类缓存
{
private HashMap cachedObjects=new HashMap();
私有静态缓存=null;
私有静态int TIME_TO_KEEP=60000;//60秒
私有最终静态对象锁=新对象();
公共静态缓存getInstance()
{
if(缓存==null)
{
缓存=新缓存();
}
返回缓存;
}
专用缓存()
{
ScheduledExecutorService executor=Executors.newScheduledThreadPool(2);
可运行任务=()->{
已同步(锁定)
{
System.out.println(“清理”);
Set keys=cachedObjects.keySet();
final long now=System.currentTimeMillis();
密钥。forEach(k->{
尝试
{
{
ObjectWrapper ow=cachedObjects.get(k);
if(ow.getExpireTime(){
System.out.println(“添加id:+++id”);
对象o=新对象();
cache.addObject(id,o);
};
带有固定延迟的执行器调度(加法器,5,10,时间单位秒);
可运行测试仪=()->{
long currTime=System.currentTimeMillis();
System.out.println(“测试:”);
Set keys=cache.getKeys();
密钥。forEach(k->{
ObjectWrapper o=cache.getObj(k);
System.out.println(k+“>”+currTime+:“+o.getExpireTime());
});
};
执行者。固定延迟的时间表(测试仪,20,10,时间单位。秒);
}
}
公共类对象包装器
{
私有对象对象;
私有长过期时间;
公共对象包装器(对象对象,长过期时间)
{
this.obj=obj;
this.expireTime=expireTime;
}
公共对象getObj()
{
返回obj;
}
公共无效设置对象(对象对象对象)
{
this.obj=obj;
}
公共长getExpireTime()
{
返回到期时间;
}
public void setExpireTime(长expireTime)
{
this.expireTime=expireTime;
}
}

考虑使用
ConcurrentHashMap
,这是一种本机线程安全的映射实现,而不是
HashMap

你的错误主要是:

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

public Set<Object> getKeys()
{
    synchronized(LOCK)
    {
        return 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;
    }
}

在对键集进行迭代时,您正在从键集中删除元素,从而产生一个
ConcurrentModificationException
,该异常在下一次迭代时抛出(在try-catch块之外)。如果将try-catch块移到循环外部:

private Cache()
{
    ScheduledExecutorService executor = Executors.newScheduledThreadPool(2);

    Runnable task = () -> {
        synchronized(LOCK)
        {
            try
            {
                System.out.println("Cleanup");
                Set<Object> keys = cachedObjects.keySet();
                final long now = System.currentTimeMillis();
                keys.forEach(k -> {

                        {
                            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);
}
相反,在键集上使用迭代器:

private Cache()
{
    ScheduledExecutorService executor = Executors.newScheduledThreadPool(2);

    Runnable task = () -> {
        synchronized(LOCK)
        {
            try
            {
                System.out.println("Cleanup");
                final long now = System.currentTimeMillis();
                final Iterator<Map.Entry<Object, ObjectWrapper>> iter = cachedObjects.entrySet().iterator();
                while (iter.hasNext()) {
                    final Map.Entry<Object, ObjectWrapper> entry = iter.next();
                    final ObjectWrapper ow = entry.getValue();
                    if(ow.getExpireTime() < now)
                    {
                        final Object k = entry.getKey();
                        int size = cachedObjects.size();
                        iter.remove();
                        System.out.println("DEL:" + k + ", from " + size + " to " + cachedObjects.size());
                    }
                }
            }
            catch (Throwable t)
            {
                t.printStackTrace();
            }
        }
    };

    executor.scheduleWithFixedDelay(task, 5, 15, TimeUnit.SECONDS);
}

谢谢,我可以通过使用ConcurrentHashMap而不是HashMap使它工作。我不确定如何使ObjectWrapper不可变,因为它只是一个嵌套对象,并且直接被其他线程更改。我确信这只是我的无知。在多线程环境中,规则是始终共享线程安全对象,因此在这里,当您共享ObjectWrapper类型的实例时,该类必须是线程安全的。我不认为在键上获取迭代器,这完全有道理,因为它将是一个新对象,从影响原始集合的任何可能更改中删除。
private Cache()
{
    ScheduledExecutorService executor = Executors.newScheduledThreadPool(2);

    Runnable task = () -> {
        synchronized(LOCK)
        {
            try
            {
                System.out.println("Cleanup");
                Set<Object> keys = cachedObjects.keySet();
                final long now = System.currentTimeMillis();
                keys.forEach(k -> {

                        {
                            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);
}
java.util.ConcurrentModificationException
        at java.util.HashMap$KeySet.forEach(HashMap.java:935)
        at Cache.lambda$new$1(Cache.java:32)
        at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
        at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:308)
        at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:180)
        at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:294)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
        at java.lang.Thread.run(Thread.java:745)
private Cache()
{
    ScheduledExecutorService executor = Executors.newScheduledThreadPool(2);

    Runnable task = () -> {
        synchronized(LOCK)
        {
            try
            {
                System.out.println("Cleanup");
                final long now = System.currentTimeMillis();
                final Iterator<Map.Entry<Object, ObjectWrapper>> iter = cachedObjects.entrySet().iterator();
                while (iter.hasNext()) {
                    final Map.Entry<Object, ObjectWrapper> entry = iter.next();
                    final ObjectWrapper ow = entry.getValue();
                    if(ow.getExpireTime() < now)
                    {
                        final Object k = entry.getKey();
                        int size = cachedObjects.size();
                        iter.remove();
                        System.out.println("DEL:" + k + ", from " + size + " to " + cachedObjects.size());
                    }
                }
            }
            catch (Throwable t)
            {
                t.printStackTrace();
            }
        }
    };

    executor.scheduleWithFixedDelay(task, 5, 15, TimeUnit.SECONDS);
}
Cleanup
Adding id:1
Adding id:2
Cleanup
Test:
1>1467228864763::1467228909763
2>1467228864763::1467228919764
Adding id:3
Test:
1>1467228874766::1467228909763
2>1467228874766::1467228919764
3>1467228874766::1467228929764
Cleanup
Adding id:4
Test:
1>1467228884766::1467228909763
2>1467228884766::1467228919764
3>1467228884766::1467228929764
4>1467228884766::1467228939764
Adding id:5
Cleanup
Test:
1>1467228894770::1467228909763
2>1467228894770::1467228919764
3>1467228894770::1467228929764
4>1467228894770::1467228939764
5>1467228894770::1467228949765
Adding id:6
Test:
1>1467228904771::1467228909763
2>1467228904771::1467228919764
3>1467228904771::1467228929764
4>1467228904771::1467228939764
5>1467228904771::1467228949765
6>1467228904771::1467228959765
Cleanup
Adding id:7
Test:
1>1467228914771::1467228909763
2>1467228914771::1467228919764
3>1467228914771::1467228929764
4>1467228914771::1467228939764
5>1467228914771::1467228949765
6>1467228914771::1467228959765
7>1467228914771::1467228969765
Adding id:8
Cleanup
DEL:1, from 8 to 7
DEL:2, from 7 to 6
Test:
3>1467228924772::1467228929764
4>1467228924772::1467228939764
5>1467228924772::1467228949765
6>1467228924772::1467228959765
7>1467228924772::1467228969765
8>1467228924772::1467228979765
Adding id:9
Test:
3>1467228934772::1467228929764
4>1467228934772::1467228939764
5>1467228934772::1467228949765
6>1467228934772::1467228959765
7>1467228934772::1467228969765
8>1467228934772::1467228979765
9>1467228934772::1467228989766
Cleanup
DEL:3, from 7 to 6
Adding id:10
Test:
4>1467228944773::1467228939764
5>1467228944773::1467228949765
6>1467228944773::1467228959765
7>1467228944773::1467228969765
8>1467228944773::1467228979765
9>1467228944773::1467228989766
10>1467228944773::1467228999766
Adding id:11
Cleanup
DEL:4, from 8 to 7
DEL:5, from 7 to 6
Test:
6>1467228954773::1467228959765
7>1467228954773::1467228969765
8>1467228954773::1467228979765
9>1467228954773::1467228989766
10>1467228954773::1467228999766
11>1467228954773::1467229009766
Adding id:12
Test:
6>1467228964774::1467228959765
7>1467228964774::1467228969765
8>1467228964774::1467228979765
9>1467228964774::1467228989766
10>1467228964774::1467228999766
11>1467228964774::1467229009766
12>1467228964774::1467229019767
Cleanup
DEL:6, from 7 to 6
Adding id:13