【发布时间】:2021-04-06 13:17:10
【问题描述】:
我正在尝试演示如何使用 synchronized 关键字修复 RaceCondition。下面的代码由一个 ZooStock 对象的变量组成,该变量由 4 个线程递增和打印。我已经同步了方法(addGrass())但是所有线程打印的值都是相同的,即
当前输出: 1002g, 1002g, 1002g, 1002g
预期输出: 1001g, 1002g, 1003g, 1004g
public static void main(String[] args){
ZooStockSync zooStockNew = new ZooStockSync(1000, 750, 5000);
ExecutorService executorService = null;
try{
executorService = Executors.newFixedThreadPool(10); //Creating a Thread pool of size 10
for(int i=0; i<4; i++){
executorService.submit(()->new ZooWorkerSync(zooStockNew).addGrass()); //
}
}finally{
if(executorService != null) executorService.shutdown();
}
}
包含同步方法的类:
class ZooWorkerSync implements Runnable {
ZooStockSync zooStock;
ZooWorkerSync(ZooStockSync zooStock){
this.zooStock = zooStock;
}
public synchronized void addGrass(){
zooStock.grass++;
System.out.print(zooStock.grass + "g ");
}
}
但是,当我在不使用 java.util.concurrent 包中的 Executor 线程的情况下以传统 (java.lang.Thread) 意义创建线程时。
public static void main(String[] args){
ZooStockSync zooStockTraditional = new ZooStockSync(1000, 750, 5000);
ZooWorkerSync[] workerThreads = new ZooWorkerSync[4]; //Set all elements in the array to be a ZooWorker object
Arrays.fill(workerThreads, new ZooWorkerSync(zooStockTraditional));
for (ZooWorkerSync workerThread : workerThreads) {
new Thread(workerThread).start(); //Start the worker threads off (this invokes the run method in the ZooWorker class)
}
}
输出如预期:1001g 5010w 751h 1002g 5020w 752h 1003g 5030w 753h 1004g 5040w 754h,注意 g 是按预期升序排列的。 (忽略 h 和 w)
工作线程的run方法如下图:
@Override
public void run() {
addGrass();
addWater();
addHay();
}
所以我的问题是,为什么 2 个输出不同,为什么我使用 java.util.concurent Executors 的线程打印出与传统方法相反的相同值?
【问题讨论】:
-
synchronized在方法上意味着您正在对对象本身进行同步,并且由于您创建了 4 个不同的ZooWorkerSync对象,每个线程一个对象,因此同步该方法无效。 -
你认为
Arrays.fill(workerThreads, new ZooWorkerSync(zooStockTraditional));是做什么的?提示:不使用每个索引的新实例填充数组。 -
@akuzminykh 嘿,所以我相信 Arrays.fill() 基本上将数组的每个索引设置为使用相同的 ZooWorkerSync 实例填充,我相信我使用我创建的执行程序线程的示例一个新的实例。我不应该这样做,因为同步被用作实例级锁,因此跨多个实例同步是多余的。我需要 1 个实例和多个线程。
标签: java multithreading concurrency synchronization java.util.concurrent