【问题标题】:Creating a deep copy of cache in mulithreaded Java application在多线程 Java 应用程序中创建缓存的深层副本
【发布时间】:2019-02-16 12:38:51
【问题描述】:

设置

我有一个多线程 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 的列表。

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

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. 所有的克隆方法在性能方面看起来都不是很好。

【问题讨论】:

  • 似乎是一个同步问题,为什么不使用 locks 在cache 上同步,这会导致性能问题,但至少您不必创建克隆。另一种方法是对您创建的cache 的克隆施加限制。前者可以使用Locks 实现,后者使用Semaphores

标签: java multithreading performance deep-copy


【解决方案1】:

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-03-05
    • 1970-01-01
    • 1970-01-01
    • 2012-05-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多