【问题标题】:Java - why waiting for multiple semaphores doesn't work?Java - 为什么等待多个信号量不起作用?
【发布时间】: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


    【解决方案1】:

    上面的代码确实有效...

    我遇到的问题与List&lt;Job&gt; jobs 参数有关。由于它不是不可修改的集合,因此在锁定期间该集合被更改并导致意外异常。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-12-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-10-21
      • 1970-01-01
      • 1970-01-01
      • 2013-05-14
      相关资源
      最近更新 更多