Java 我的并发代码是同步的,但它不同步打印值,但是每个线程打印相同的值
我试图演示如何使用synchronized关键字修复竞争条件。下面的代码由一个ZooStock对象变量组成,该变量由4个线程递增并打印。我已经同步了方法(addGrass()),但是所有线程打印的值都是相同的,即 电流输出:Java 我的并发代码是同步的,但它不同步打印值,但是每个线程打印相同的值,java,multithreading,concurrency,synchronization,java.util.concurrent,Java,Multithreading,Concurrency,Synchronization,Java.util.concurrent,我试图演示如何使用synchronized关键字修复竞争条件。下面的代码由一个ZooStock对象变量组成,该变量由4个线程递增并打印。我已经同步了方法(addGrass()),但是所有线程打印的值都是相同的,即 电流输出:1002g、1002g、1002g、1002g 预期输出:1001g、1002g、1003g、1004g public static void main(String[] args){ ZooStockSync zooStockNew = new Zo
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();
}
}
但是,当我在传统意义上(java.lang.Thread)创建线程时,没有使用java.util.concurrent包中的执行器线程
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)
工作线程的运行方法如下所示:
@Override
public void run() {
addGrass();
addWater();
addHay();
}
所以我的问题是,为什么这两个输出不同,为什么我使用java.util.concurent执行器的线程来打印相同的值,而不是传统的方法?我没有看到ZooStockSync的代码,但它看起来像是在线程(ZooWorkerSync)上同步一个方法,而不是在共享对象。然后访问ZooStockSync中的字段:
public synchronized void addGrass(){
zooStock.grass++;
System.out.print(zooStock.grass + "g ");
}
但进入该区域(草地)可能不是线程安全的。每个ZooWorkerSync线程都可以同时访问该字段。我建议将synchronized放在ZooStockSync中的一个方法上,以增加字段。例如:
public synchronized void incrementGrass() {
grass++;
}
您还可以对草地字段使用volatile关键字,或将其设为。
同步的
锁定一个对象,并且由于您在多个对象上同步,因此该对象无法按您所希望的方式工作
相反,您应该在公共对象(如类)上进行同步
class ZooWorkerSync implements Runnable {
ZooStockSync zooStock;
ZooWorkerSync(ZooStockSync zooStock){
this.zooStock = zooStock;
}
public void addGrass(){
synchronized (ZooWorkerSync.class) {
zooStock.grass++;
System.out.print(zooStock.grass + "g ");
}
}
}
在
ExeutorService
示例中,您正在创建ZooWorkerSync
类的多个实例,在Thread
示例中,您正在重用同一实例
在第一个示例中,
synchronized
关键字实际上没有任何作用,因为它是一个实例级锁。您可以尝试在类上手动同步。错误源于我创建了几个ZooWorkerSync实例。在Executors示例中,使用上面演示的单词synchronized作为实例级锁,因此在多个实例之间实际上是冗余的,它只对单个实例有用,因此我需要修改executorService,以便仅从单个实例调用addGrass():
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
ZooWorkerSync zooWorkerSync = new ZooWorkerSync(zooStockNew);
for(int i=0; i<4; i++){
executorService.submit(zooWorkerSync::addGrass);
}
}finally{
if(executorService != null) executorService.shutdown();
}
}
publicstaticvoidmain(字符串[]args){
ZooStockSync zooStockNew=新的ZooStockSync(10007505000);
ExecutorService ExecutorService=null;
试一试{
executorService=Executors.newFixedThreadPool(10);//创建大小为10的线程池
ZooWorkerSync ZooWorkerSync=新建ZooWorkerSync(zooStockNew);
对于(int i=0;isynchronized
在一个方法上意味着在对象本身上同步,并且由于您创建了4个不同的ZooWorkerSync
对象,每个线程一个,因此同步该方法没有效果。您认为Arrays.fill(workerThreads,new ZooWorkerSync(zooStockTraditional))如何
有吗?提示:不要用每个索引的新实例填充数组。@akuzminykh嘿,所以我相信Arrays.fill()基本上,将数组的每个索引设置为使用ZooWorkerSync的同一个实例填充,我相信我使用executor线程创建了一个新实例的示例。我不应该这样做,因为synchronized用作实例级锁,因此跨多个实例的同步是冗余的。我需要1个实例和mult多根线。
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
ZooWorkerSync zooWorkerSync = new ZooWorkerSync(zooStockNew);
for(int i=0; i<4; i++){
executorService.submit(zooWorkerSync::addGrass);
}
}finally{
if(executorService != null) executorService.shutdown();
}
}