当前位置: 首页 > >

高并发无锁实现代码块只进入一次小技巧

发布时间:

源:http://kenwublog.com/concurrent-no-lock-tech-tip

public static void main(String[] args) throws InterruptedException {

final CyclicBarrier barrier = new CyclicBarrier(50); // 50个并发

final long interval = 5000; // 每5秒

Holder.time.set(System.currentTimeMillis());// 起始时间

for (int i = 0; i < 100; i++) {

new Thread() {

@Override

public void run() {

while (true) {

long now = System.currentTimeMillis();

// 时间原子操作+原子计数器实现无锁单线程进入

if (now - Holder.time.get() > interval && Holder.count.incrementAndGet() == 1) {

System.out.println("function block entered");

Holder.time.set(now);

Holder.count = new AtomicLong();

}

}

}

}.start();

}

}

static class Holder {

public static volatile AtomicLong time = new AtomicLong();

public static AtomicLong count = new AtomicLong();

}



}



其实思路也比较简单,首先通过计数器保证同一时刻只能进入一个线程,然后重置时间,最后重置计数器,亮点是计数器的重置只能通过new,不能set(0),set(0)会导致同一时刻其余并发线程看到0值,从而误进入代码块。而new可以保证其他并发线程一直hold在老的对象上累加,new只对后面的新线程起到可见性(volatile),加上之前的时间已经重置,条件判断里能严格保证代码块只进入一次。



当然,这种情况也只能保证99.9%的场景,在多核场景下如果系统做了CPU指令重排序后,那就有可能不止一次进入,我通过压测1000个线程,就出现过1次进入了2次。但基本也满足我的场景需要了。



友情链接: