【发布时间】:2020-09-24 14:18:03
【问题描述】:
我有一些作业(同时更新和保存)我不想一起保存到数据库中,这会导致乐观锁异常。
例如: - 我们有 10 个长时间运行的作业由 10 个不同的线程处理 - 工作完成后,将其结果(成功或失败)保存到数据库中 - 有一个心跳线程更新所有仍在处理的作业并批量保存
我可以在保存一个或一个时锁定整个存储库,但这在性能方面是个坏主意(几个不同的作业可以同时进入成功状态)。
我的想法是自己锁定作业:
public abstract class AbstractJob implements Lockable {
***
private transient final Lock lock;
protected AbstractJob() {
lock = new Lock();
}
***
public Lock lock() {
return lock.lock();
}
}
锁定是通过我的数据库存储库周围的包装器完成的:
public class ThreadSafeStorageProvider implements StorageProvider{
private final StorageProvider storageProvider;
public ThreadSafeStorageProvider(StorageProvider storageProvider) {
this.storageProvider = storageProvider;
}
...
@Override
public Job save(Job job) {
try(Lock lock = job.lock()) {
return storageProvider.save(job);
}
}
@Override
public List<Job> save(List<Job> jobs) {
try(MultiLock lock = new MultiLock(jobs)) {
return storageProvider.save(jobs);
}
}
...
}
锁在内部使用信号量来获取和释放锁。
public class Lock implements AutoCloseable {
private final Semaphore semaphore;
public Lock() {
this.semaphore = new Semaphore(1);
}
public Lock lock() {
semaphore.acquireUninterruptibly();
return this;
}
public void close() {
unlock();
}
public void unlock() {
semaphore.release();
}
}
MultiLock 获取作业列表(Locables),锁定它们,保存所有作业并再次释放所有锁。
public class MultiLock implements Closeable {
private final Collection<Lock> locks;
public MultiLock(Lockable... lockables) {
this(Arrays.asList(lockables));
}
public MultiLock(Collection<? extends Lockable> lockables) {
this.locks = lockables.parallelStream().map(Lockable::lock).collect(toList());
}
public void unlock() {
locks.forEach(Lock::unlock);
}
@Override
public void close() {
unlock();
}
}
然而,这一切仍然会导致乐观锁异常...
我尝试过的事情:
- 使用
ReentrantLock而不是Semaphore-> 仍会导致乐观锁异常 - 而不是
parallelStream()使用普通的stream()-> 慢得多,并且仍然会导致乐观锁异常
我做错了什么?
【问题讨论】:
标签: java multithreading parallel-processing semaphore