在多线程Java应用程序中创建缓存的深层副本

问题描述 投票:1回答:1

建立

我有一个多线程Java应用程序,它将每秒接收200-300个请求,以对请求中收到的输入执行任务“A”(大约需要30毫秒)。

应用程序有一个缓存(最大大小= 1MB),每个线程读取该缓存以在收到的输入上执行任务“A”:

public class DataProvider() {

    private HashMap<KeyObject, ValueObject> cache;

    private Database database;

    // Scheduled to run in interval of 15 seconds by a background thread
    public synchronized void updateData() {
        this.cache = database.getData();
    }

    public HashMap<KeyObject, ValueObject> getCache() {
        return this.cache;
    }

}

KeyObject和ValueObject是POJO。 ValueObject包含另一个POJO的List。

对于收到的每个请求,任务都按以下方式完成:

public class TaskExecutor() {

    private DataProvider dataProvider;

    public boolean doTask(final InputObject input) {
        final HashMap<KeyObject, ValueObject> data = dataProvider.getCache();    // shallow copy I think
        // Do Task 'A' using data
    }

}

问题

其中一个线程使用缓存中的数据“d1”在时间戳“t”开始执行任务“A”。在时间't + t1',缓存数据被更新为'd2'。线程现在开始使用数据'd2'来完成剩余的任务。任务在't + t1 + t2'完成。一半的任务完成了不同的数据。这将导致任务结果无效。

目前的方法

每个线程将创建缓存的深层副本,然后使用深层副本使用以下方法之一(性能最佳)执行深层复制:

How do you make a deep copy of an object in Java?

Deep clone utility recommendation

局限性

  1. 使用深层复制进行克隆会产生数千个可能导致JVM崩溃的对象。
  2. 所有克隆方法在性能方面看起来都不好。
java multithreading performance deep-copy
1个回答
0
投票

对于您的用例,从database.getData();返回一个新的缓存是更好的选择。因为如果您选择这种方式,您只需要在15秒内创建一个新的缓存对象。如果您选择在每个任务中克隆缓存,则必须在15秒内创建4501缓存对象。显然返回新的缓存对象是正确的选择。

如果您提供的代码与您的项目中的代码相同,我相信database.getData();方法更改单个缓存对象的内容而不是返回新的。如果从此方法返回新的缓存对象,您的问题将得到解决。

© www.soinside.com 2019 - 2024. All rights reserved.