我有一个Java/Groovy多线程进程,我想在N次执行后“同步”: - 每次线程执行后共享计数器递减 - 目标是重置计数器一次它达到0,而没有其他线程正在访问它。在N次执行后协调多个线程
我试过ReadWriteReentrantLock但它看起来我有一个竞争条件的递减阶段。这里是我的测试代码
public static void main(String[] args) {
AtomicInteger counter = new AtomicInteger(Decrementer.MAX_SIZE)
ReadWriteLock lock = new ReentrantReadWriteLock()
for (int i = 1; i <= 10; i++) {
Decrementer d = new Decrementer(counter, lock)
new Thread(d).start()
}
}
public class Decrementer implements Runnable {
public final static int MAX_SIZE = 5
private ReadWriteLock lock
private AtomicInteger counter
public Decrementer(AtomicInteger counter, ReadWriteLock lock) {
this.counter = counter
this.lock = lock
}
public void run() {
while (true) {
try{
lock.readLock().lock()
int current = this.counter.decrementAndGet()
System.out.println(Thread.currentThread().getName() + " at counter " + current)
Thread.sleep(762)
} finally {
lock.readLock().unlock()
}
try {
lock.writeLock().lock()
int current = this.counter.get()
if (current <= 0) {
this.counter.set(Decrementer.MAX_SIZE)
System.out.println(Thread.currentThread().getName() + " reset " + current + " to " + Decrementer.MAX_SIZE)
Thread.sleep(4217)
}
} finally {
lock.writeLock().unlock()
}
}
}
}
这给下面的怪异输出(带负计数器值),可能是由于的AtomicInteger价值的缺失“同步”的检查。
Thread-3 at counter 2
Thread-2 at counter 4
Thread-1 at counter 3
Thread-4 at counter 1
Thread-5 at counter 0
Thread-6 at counter -1
Thread-7 at counter -2
Thread-8 at counter -3
Thread-9 at counter -4
Thread-10 at counter -5
Thread-2 reset -5 to 5
Thread-3 at counter 4
Thread-4 at counter 2
Thread-2 at counter 3
Thread-1 at counter 1
Thread-5 at counter -3
Thread-10 at counter -4
Thread-7 at counter -1
Thread-6 at counter -2
Thread-8 at counter 0
Thread-9 at counter -5
Thread-9 reset -5 to 5
我也看到了CountDownLatch和CyclicBarrier类,但我的目标是不同步的所有线程但要保证计数器复位是原子和其他线程排除其他修改。
您是否看到我在代码中遗漏的任何明显的并发问题?
感谢您的评论。你说得很对:我正在读锁中写入(到计数器)。 但是在你的解决方案中,你尝试为每个线程获取一个WriteLock,这将很快导致饥饿(实际上一次只运行一个线程) 我会跟进你的建议并将写入部分分组(递减+测试+复位计数器一起)并保持该进程的读锁(由睡眠模拟) – Wavyx
这只是一个工作示例,并非完整的解决方案。我也非常不鼓励在生产中使用Thread.sleep(4217)! :) –