【问题标题】:Two functions can run concurrently but not with other functions两个函数可以同时运行,但不能与其他函数同时运行
【发布时间】:2017-10-24 22:10:49
【问题描述】:

我有十个通用函数,它们都在我的框架中频繁运行。其中两个是 A 类函数,另外八个是 B 类函数。我希望能够同时运行 A 类函数,但不允许 B 类函数在 A 类函数运行时运行。同样,如果 B 类函数正在运行,我不希望任何 A 类函数被允许运行。如果已经在运行,我也不希望任何其他类型 B 运行。

除了使用 ReentrantReadWriteLock,使用 A 类型的读锁和 B 类型的写锁之外,还有什么更好的方法(特别是在 Java 中)?

ReentrantReadWriteLock 适用于大多数时候需要读取器锁,而“偶尔”需要写入器锁的情况。然而,在我的例子中,所有的函数都一直在使用,这意味着这些函数都以相同的频率被调用。无论我使 ReentrantReadWriteLock 公平还是不公平,我都看到我的系统中存在很多锁争用。

【问题讨论】:

  • 如果ReentrantReadWriteLock 适合您的目的,您为什么还要搜索其他内容? Java 中不太可能存在另一种机制,其行为与ReentrantReadWriteLock 相同。如果您认为 rw-lock 不能反映 A 和 B 之间相关性的性质,请提供有关这些函数的更多信息(例如,为什么它们不能同时运行)。
  • 您为什么要寻找“更好”的方法?使用ReadWriteLock 有什么问题?你想“修复”什么?仅仅是你不喜欢这些名字吗,例如如果它们被称为独占锁和共享锁,对你来说会更好吗?
  • 查看编辑以获取更多详细信息
  • 多个B方法可以同时运行吗?
  • 好问题 - 编辑问题以改进

标签: java multithreading concurrency


【解决方案1】:

ReentrantReadWriteLock 适用于大多数时候需要读取器锁,而“偶尔”需要写入器锁的情况。

我不确定你是从哪里得到这个想法的。 ReentrantReadWriteLock 在很多地方都用于完全处理您概述的情况。它被设计成高性能和(当然)可重入的,任何你可能通过手动编码拼凑起来的解决方案很可能不会表现得那么好。

但是,在我的例子中,所有函数都一直在使用,这意味着所有函数都以相同的频率被调用。

这应该没问题。您应该阅读关于“公平”的ReentrantReadWriteLock javadocs 的细则,但是 A 和 B 的任何频率都将由锁很好地处理。

总结一下文档,在“公平”模式下,如果一个 B 任务去获取写锁,它将阻塞 一组已经在等待的 A 任务。如果 A 任务被锁定,那么只有在没有 B 任务等待时才允许运行。 “不公平”模式将允许 A 任务运行,如果 B 任务连续出现,它们可能会饿死,但可能“通常比公平锁具有更高的吞吐量”。

我会坚持“公平”政策,除非您有特殊理由不这样做。

无论我使 ReentrantReadWriteLock 公平还是不公平,我都发现我的系统中有很多锁争用。

我认为这是意料之中的。无论您想出什么解决方案,如果您有 A 和 B 任务以下降频率执行,您将遇到锁争用。也许如果您编辑了您的问题并提供了更多关于您认为争用出乎意料的原因的详细信息,我们可以提供更好的答案。

我希望能够同时运行 A 类函数,但不允许 B 类函数在 A 类函数运行时运行。

所以 A 任务将使用 ReentrantReadWriteLockread 部分:

private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
private final Lock readLock = readWriteLock.readLock();
private final Lock writeLock = readWriteLock.writeLock();
...
private void functionA() {
    readLock.lock();
    try {
       // do the A processing here ...
    } finally {
       readLock.unlock();
    }
}

如果 B 类函数正在运行,我不希望任何 A 类函数被允许运行。如果已经在运行,我也不希望任何其他类型 B 运行。

所以 B 任务将使用锁的写入部分:

private void functionB() {
    writeLock.lock();
    try {
       // do the B processing here ...
    } finally {
       writeLock.unlock();
    }
}

【讨论】:

  • 我想指出,我正在寻找更好的解决方案的原因是,在docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/… 的文档中,它说“ReentrantReadWriteLocks 可用于提高某些集合的某些用途的并发性。这通常只有在预期集合很大、由更多读取线程而不是写入线程访问并且需要开销超过同步开销的操作时才值得。“感谢您解释我遇到的争用是正常的。
  • 对@KeyanRhm。我怀疑你引用的语句试图指出,通过使用这个锁,你并没有从 synchronized 关键字的开销中节省多少。
猜你喜欢
  • 2017-07-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-09-01
  • 1970-01-01
相关资源
最近更新 更多