Java 检测方法的并发调用

Java 检测方法的并发调用,java,multithreading,concurrency,lock-free,optimistic-concurrency,Java,Multithreading,Concurrency,Lock Free,Optimistic Concurrency,我有一个类序列化程序: class Serializer<T> extends Consumer<T> { final Consumer<? super T> actual; // constructor omitted for brewity @Override public synchronized void accept(T t) { actual.accept(t); } } 类序列化程序扩展使用者{

我有一个类序列化程序:

class Serializer<T> extends Consumer<T> {
    final Consumer<? super T> actual;
    // constructor omitted for brewity
    @Override public synchronized void accept(T t) {
         actual.accept(t);
    }
}
类序列化程序扩展使用者{

最终消费者这就是synchronized为您所做的。(它在其他策略中使用了偏向锁定)

如果您想知道是否有一种更有效的方法可以在一般情况下同步数据,那么如果您能够超越数十年来在这一领域的专业知识,我会感到非常惊讶。如果您确实找到一种更快的方法来出名,那就是“kd304锁定策略”


如果你问是否有办法减少特定/特殊情况下代码段的开销,那么肯定有办法,但这取决于你在做什么,这一点从问题上看还不清楚。

正如其他人所说,
synchronized
已经为你提供了一个相当有效的工具。因此,使用不同的工具不应该是动机希望能有更好的表现,这让我感到很沮丧

然而,如果你的意图不是像你在问题中所说的那样阻止呼叫者,那么这是合法的(尽管这可能意味着你的生活表现较差)

在查看您使用队列和原子整数的尝试时,我看到的第一件事是,如果没有挂起的项目,也没有其他使用者正在运行,则可以绕过队列。如果争用率较低,则可能会降低开销:

final ConcurrentLinkedQueue<T> queue;
final AtomicInteger wip;
@Override public void accept(T t) {
  if(wip.compareAndSet(0, 1)) { // no contention?
    actual.accept(t);
    if(wip.decrementAndGet()==0) return; // still no contention
  }
  else {
    if(!queue.offer(t))
      throw new AssertionError("queue should be unbounded");
    if(wip.getAndIncrement() != 0) return; // other consumer running
  }
  do {
    actual.accept(queue.poll());
  } while (wip.decrementAndGet() > 0);
}
最终ConcurrentLinkedQueue队列;
最终原子整数在制品;
@覆盖公共无效接受(T){
如果(wip.compareAndSet(0,1)){//没有争用?
实际接受(t);
if(wip.decrementAndGet()==0)返回;//仍然没有争用
}
否则{
如果(!queue.offer(t))
抛出新的断言错误(“队列应该是无界的”);
if(wip.getAndIncrement()!=0)返回;//正在运行的其他使用者
}
做{
actual.accept(queue.poll());
}而(wip.decrementAndGet()>0);
}

如果您的代码必须是单线程的,我不确定它可以如何扩展…此逻辑和类是数据流库的一部分,其中有一个操作符可以将多个数据流合并到一个流中,如果每个流可能在其自己的线程中生成。扩展来自多个生产者的并发序列化方式:juc锁似乎工作得最好,但是当只有一个数据流处于活动状态而其他数据流出于某种原因处于休眠状态时,锁的开销太大了。在这种情况下,我想消除同步开销。我要求减少开销。环境是RxJava库及其SerializedDobServer,如果可能的话,我打算改进它e、 目前,它使用的同步块在单线程使用上的开销较低,但如果多个线程同时使用,juc.Lock提供更好的吞吐量。在数字上,一个直接调用产生300 Mops/s,同步在一些提升后产生100 Mops/s,juc.Lock提供18 Mops/s。对于两个线程的堆积,synchronized提供15 Mops/sps/s,而juc.Lock提供21 Mops/s。这一优势似乎保留在线程数较高的情况下。@kd304进一步优化代码将需要分析代码所做的工作。也许您可以将其更改为并发,或者减少需要持有锁的时间,或者使用带戳的锁。谢谢,这绝对是一个改进单线程调用的nt:我得到的是40Mops/s,而不是18Mops。不幸的是,else子句给出的是6-10 Mops/s,而juc.Lock给出的是16Mops/s。然而,我怀疑,由于juc.Lock停止,吞吐量实际上是通过引入大延迟来实现的。我将尝试其他一些技术来提高所有情况下的吞吐量。@kd304:A
Lock
基本上是一个原子整数,在没有争用的情况下与上面的代码类似。我希望在单线程的情况下具有类似的性能。只有在锁定失败时,线程才会被暂停(我假设您不使用“公平”锁)。如果您遇到不同的结果,请发布基于
锁定的解决方案代码,我们可以查看一下……感谢您的想法。我通过自适应地启用和禁用快速路径,成功地回收了一些吞吐量。
final ConcurrentLinkedQueue<T> queue;
final AtomicInteger wip;
@Override public void accept(T t) {
  if(wip.compareAndSet(0, 1)) { // no contention?
    actual.accept(t);
    if(wip.decrementAndGet()==0) return; // still no contention
  }
  else {
    if(!queue.offer(t))
      throw new AssertionError("queue should be unbounded");
    if(wip.getAndIncrement() != 0) return; // other consumer running
  }
  do {
    actual.accept(queue.poll());
  } while (wip.decrementAndGet() > 0);
}