【发布时间】: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
限制
使用深拷贝进行克隆会创建数千个可能导致 JVM 崩溃的对象。
所有的克隆方法在性能方面看起来都不是很好。
【问题讨论】:
-
似乎是一个同步问题,为什么不使用 locks 在
cache上同步,这会导致性能问题,但至少您不必创建克隆。另一种方法是对您创建的cache的克隆施加限制。前者可以使用Locks 实现,后者使用Semaphores。
标签: java multithreading performance deep-copy