Java同步的方法调用主要来自同一线程

时间:2019-03-31 20:10:08

标签: java multithreading concurrency

我在一个具有可变状态的类中有一个方法,该方法从单个线程被称为99.999%,除了在关闭钩子中从另一个线程获得一次。

这里是班级的骨架

public class StateHolder {
    private final Queue<String> q;

    public synchronized void add(String s) {
       this.q.offer(s);
       this.lastUpdateTime = System.currentTimeMillis();
    }

    public synchronized void removeUntil(Predicate<String> p) {
        while(!q.isEmpty()) {
           if (p.applies(q.peek()) {
                q.poll();
            } else {
                break;
            }
        }
        this.lastUpdateTime = System.currentTimeMillis();
    }

    public synchronized int pendingRecords() {
        return this.q.size();
    }

    public synchronized void shutdown(Consumer<String> c) {
        while(!q.isEmpty()) c.accept(q.poll());
    }
}

在上面的方法中,在应用程序的生命周期中,方法addpendingRecordsremoveUntil总是从同一线程中调用(每秒1000次以上的调用取决于所访问的流量)。应用程序)。 shutdown将在应用程序关闭期间由其他线程调用,这将在几周内发生一次。

是否有一个同步原语被认为是此访问模式的更好性能选择?还是应该只使用传统的synchronized块并让JIT找出来?

2 个答案:

答案 0 :(得分:1)

我相信您会(开箱即用)利用偏置锁定-Biased locking in java

答案 1 :(得分:0)

首先,当同时发生对add的调用时,需要弄清对pendingRecordsremoveUntilshutdown的调用的语义。在当前的实现中,这些调用将被阻止,直到shutdown返回为止,但是之后它们将很高兴地继续执行。在这种情况下,可能最好抛出IllegalStateException。但这确实取决于您的要求。

为了改善并发方面,我将shutdown的生命周期问题与其余应用程序逻辑分开。例如,您可以将qQueue<String>更改为AtomicReference<Queue<String>>。然后,对shutdown的调用会将对该引用的引用设置为Queue的实现,该实现表示正在进行的关闭,例如将IllegalStateException放在所有方法上。根据所需的确切语义,还有其他与并发相关的问题需要解决。例如。 removeUntil在循环中间开始失败是否正常?如果不是,则该方法将需要从进入该方法时获取的队列的本地副本进行操作。