为什么竞争条件只能用 ReentrantLock 解决而不是同步
Why race condition is only solved with ReentrantLock and not synchronized
我尝试使用多线程将所有元素添加到我的结果列表中。我不确定为什么结果看起来很奇怪。
public class PrintMessage {
public static void main(String[] args) {
PrintMessage p = new PrintMessage();
List<String> list = List.of("a", "b", "c", "d", "e", "f", "g", "h");
ExecutorService executor = Executors.newFixedThreadPool(5);
p.printValue(list, executor);
try {
executor.awaitTermination(1000, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
}
executor.shutdown();
System.out.println(res);
}
//ReentrantLock lock = new ReentrantLock();
private volatile int index = 0;
static List<String> res = new ArrayList<>();
class Printer implements Runnable {
List<String> list;
public Printer(List<String> list) {
this.list = list;
}
@Override
public void run() {
//lock.lock();
pickItem(index, list);
//increment();
//lock.unlock();
}
}
private void increment() {
index++;
}
private synchronized void pickItem(int index, List<String> list) {
res.add(list.get(index));
increment();
}
public void printValue(List<String> list, ExecutorService executor) {
for (int i = 0; i < list.size(); i++) {
executor.submit(new Printer(list));
}
}
}
不确定为什么索引没有被其他线程更改,当我更改 synchronized 并使用 ReentrantLock 锁定 pick() 时,增量()方法。结果看起来不错。有人可以解释原因吗?非常感谢。
[a, b, c, e, e, f, a, a]
Not sure why does the index not change by other threads, when I change
synchronized and use ReentrantLock to lock pick(), increment()
methods. the result looks good. Can someone explain the reason? Many
thanks.
方法上的synchronized
private synchronized void pickItem(int index, List<String> list) {
res.add(list.get(index));
increment();
}
正在使用 class Printer
的 this
返回的对象实例的 隐式 锁进行锁定,因为对于每个 Thread
创建了 Printer
class 的新对象实例:
for (int i = 0; i < list.size(); i++) {
executor.submit(new Printer(list));
}
每个线程在 class Printer
的不同实例上调用 synchronized
。因此,这些线程 未使用相同的 lock
进行锁定,因此存在 竞争条件 .
然而,lock
变量
ReentrantLock lock = new ReentrantLock();
是对象PrintMessage
的字段变量,所有线程共享。因此,当线程调用 lock.lock();
和 lock.unlock();
时,它们使用相同的(共享)锁,因此不再存在上述 race-condition.
单独使用 ReentrantLock
(方法 pickItem
上没有 synchronized
)解决上述 race-condition.
我尝试使用多线程将所有元素添加到我的结果列表中。我不确定为什么结果看起来很奇怪。
public class PrintMessage {
public static void main(String[] args) {
PrintMessage p = new PrintMessage();
List<String> list = List.of("a", "b", "c", "d", "e", "f", "g", "h");
ExecutorService executor = Executors.newFixedThreadPool(5);
p.printValue(list, executor);
try {
executor.awaitTermination(1000, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
}
executor.shutdown();
System.out.println(res);
}
//ReentrantLock lock = new ReentrantLock();
private volatile int index = 0;
static List<String> res = new ArrayList<>();
class Printer implements Runnable {
List<String> list;
public Printer(List<String> list) {
this.list = list;
}
@Override
public void run() {
//lock.lock();
pickItem(index, list);
//increment();
//lock.unlock();
}
}
private void increment() {
index++;
}
private synchronized void pickItem(int index, List<String> list) {
res.add(list.get(index));
increment();
}
public void printValue(List<String> list, ExecutorService executor) {
for (int i = 0; i < list.size(); i++) {
executor.submit(new Printer(list));
}
}
}
不确定为什么索引没有被其他线程更改,当我更改 synchronized 并使用 ReentrantLock 锁定 pick() 时,增量()方法。结果看起来不错。有人可以解释原因吗?非常感谢。
[a, b, c, e, e, f, a, a]
Not sure why does the index not change by other threads, when I change synchronized and use ReentrantLock to lock pick(), increment() methods. the result looks good. Can someone explain the reason? Many thanks.
方法上的synchronized
private synchronized void pickItem(int index, List<String> list) {
res.add(list.get(index));
increment();
}
正在使用 class Printer
的 this
返回的对象实例的 隐式 锁进行锁定,因为对于每个 Thread
创建了 Printer
class 的新对象实例:
for (int i = 0; i < list.size(); i++) {
executor.submit(new Printer(list));
}
每个线程在 class Printer
的不同实例上调用 synchronized
。因此,这些线程 未使用相同的 lock
进行锁定,因此存在 竞争条件 .
然而,lock
变量
ReentrantLock lock = new ReentrantLock();
是对象PrintMessage
的字段变量,所有线程共享。因此,当线程调用 lock.lock();
和 lock.unlock();
时,它们使用相同的(共享)锁,因此不再存在上述 race-condition.
单独使用 ReentrantLock
(方法 pickItem
上没有 synchronized
)解决上述 race-condition.