Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 我的并发代码是同步的,但它不同步打印值,但是每个线程打印相同的值_Java_Multithreading_Concurrency_Synchronization_Java.util.concurrent - Fatal编程技术网

Java 我的并发代码是同步的,但它不同步打印值,但是每个线程打印相同的值

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

我试图演示如何使用synchronized关键字修复竞争条件。下面的代码由一个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();
          }
      }
但是,当我在传统意义上(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;i
synchronized
在一个方法上意味着在对象本身上同步,并且由于您创建了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();
          }
  }