我在一个具有可变状态的类中有一个方法,该方法从单个线程被称为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());
}
}
在上面的方法中,在应用程序的生命周期中,方法add
,pendingRecords
和removeUntil
总是从同一线程中调用(每秒1000次以上的调用取决于所访问的流量)。应用程序)。 shutdown
将在应用程序关闭期间由其他线程调用,这将在几周内发生一次。
是否有一个同步原语被认为是此访问模式的更好性能选择?还是应该只使用传统的synchronized
块并让JIT找出来?
答案 0 :(得分:1)
我相信您会(开箱即用)利用偏置锁定-Biased locking in java
答案 1 :(得分:0)
首先,当同时发生对add
的调用时,需要弄清对pendingRecords
,removeUntil
和shutdown
的调用的语义。在当前的实现中,这些调用将被阻止,直到shutdown
返回为止,但是之后它们将很高兴地继续执行。在这种情况下,可能最好抛出IllegalStateException
。但这确实取决于您的要求。
为了改善并发方面,我将shutdown
的生命周期问题与其余应用程序逻辑分开。例如,您可以将q
从Queue<String>
更改为AtomicReference<Queue<String>>
。然后,对shutdown
的调用会将对该引用的引用设置为Queue
的实现,该实现表示正在进行的关闭,例如将IllegalStateException
放在所有方法上。根据所需的确切语义,还有其他与并发相关的问题需要解决。例如。 removeUntil
在循环中间开始失败是否正常?如果不是,则该方法将需要从进入该方法时获取的队列的本地副本进行操作。