我需要在5个线程中增加一个计数器,直到它达到500.像这样的5个线程正在工作。但我需要知道它是否有竞争条件。
此代码的另一个问题是它以错误的顺序给我打印。
class HiloContador extends Thread {
static int count = 0;
@Override
public void run() {
for (int i = 0; i < 100; i++) {
synchronized (new Integer(count)) {
++count;
System.out.println(count);
}
}
}
}
4 6 8 9 10 11 12 五 14 15 3 17 18
一些想法?
答案 0 :(得分:4)
是的,存在竞争条件,因为您实际上在不同对象上同步代码。 synchronized块代表一个关键部分。要进入关键部分,您必须获得全局锁定。您可以将对象用于锁定或整数。 这就是我要实现的方式:
class HiloContador extends Thread {
static int count = 0;
static Object lock = new Object();
@Override
public void run() {
for (int i = 0; i < 100; i++) {
synchronized (lock) {
++count;
System.out.println(count);
}
}
}
}
现在println将处于预期的顺序。
答案 1 :(得分:2)
此代码中是否存在竞争条件?
是的,存在竞争条件:此行表示不正确的同步:
synchronized (new Integer(count)) {
这就是为什么。
我们来参考文档:
每个对象都有一个与之关联的内在锁。按照惯例,需要对对象字段进行独占和一致访问的线程必须在访问对象之前获取对象的内部锁,然后在完成它们时释放内部锁。据说一个线程在获得锁定和释放锁定之间拥有内在锁定。只要一个线程拥有一个内部锁,没有其他线程可以获得相同的锁。另一个线程在尝试获取锁时会阻塞。
- Intrinsic Locks and Synchronization (The Java™ Tutorials > Essential Classes > Concurrency)。
在目前的情况下,第一句话很关键。当前实现使用新对象的内部锁来在每次循环迭代时进行同步。这是不正确的。
实现增量操作原子性的替代方法:
synchronized
关键字)。请参阅Intrinsic Locks and Synchronization (The Java™ Tutorials > Essential Classes > Concurrency)文章。java.util.concurrent.atomic
包:AtomicBoolean
,AtomicInteger
,AtomicLong
等类。请参阅Atomic Variables (The Java™ Tutorials > Essential Classes > Concurrency)文章。java.util.concurrent.locks
包的类)。请参阅Lock Objects (The Java™ Tutorials > Essential Classes > Concurrency)文章。让我们使用原子变量(解决方案#3),即AtomicInteger
类:它具有内置的所需功能。
另外,我们不要扩展Thread
类:让我们提取相应的Runnable
接口实现。
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
public class Program {
public static void main(String[] args) throws InterruptedException {
final CountingRunnable countingRunnable = new CountingRunnable();
final List<Thread> threads = new ArrayList<>();
for (int i = 0; i < 5; ++i) {
final Thread thread = new Thread(countingRunnable);
threads.add(thread);
thread.start();
}
for (final Thread thread : threads) {
thread.join();
}
}
private static final class CountingRunnable implements Runnable {
private final AtomicInteger count = new AtomicInteger(0);
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(count.incrementAndGet());
}
}
}
}