【问题标题】:Update multithreading cells based on neighbor's value. How to continue with CyclicBarrier?根据邻居的值更新多线程单元。如何继续使用 CyclicBarrier?
【发布时间】:2019-09-21 05:11:30
【问题描述】:

我正在尝试完成以下工作:

  1. 从用户那里获得两个输入(lengthamountOfCycles
  2. 创建一个包含length 线程数量的数组。每个都包含value 范围内的整数[1, 100]
  3. 循环amountOfCycles + 1 次数并在每次迭代时执行以下操作:
    1. 打印数组的值。
    2. 根据其(循环)邻居更新数组中的每个值:
      • 如果值小于两个邻居的值:将值增加 1
      • 如果值大于两个邻居的值:将值减小 1
      • 如果当前值小于或等于一个邻居,并且大于或等于另一个邻居:保持该值不变

根据它们的邻居更新这些值是多线程的原因。 请注意,这只是练习多线程的东西。通过简单地一起删除线程并创建数组的副本(which I already did),我可以轻松地完成上述操作。

到目前为止,这是我的代码:

import java.util.Arrays;
import java.util.Scanner;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

public class Main{
  Cell[] cells;
  CyclicBarrier barrier;
  int length, amountOfCycles;

  Main(){
    Scanner stdin = new Scanner(System.in);
    length = stdin.nextInt();
    amountOfCycles = stdin.nextInt();
    barrier = new CyclicBarrier(length);
    cells = new Cell[length];
    for(int i=0; i<length; i++)
      cells[i] = new Cell(i);
  }

  public static void main(String[] args){
    Main program = new Main();
    program.start();
  }

  void start(){
    for(int i=0; i<length; i++)
      cells[i].run();

    for(int cycle = amountOfCycles; cycle >= 0; cycle--)
      System.out.println(Arrays.toString(cells));
  }

  class Cell implements Runnable{
    int value,
        index;

    Cell(int i){
      index = i;
      value = (int)(Math.random() * 100) + 1; // Random integer within the range [1, 100]
    }

    @Override
    public void run(){
      try{
        // Wait for the start of the cycle:
        barrier.wait();

        // Determine the increment for the value of this cell:
        // Get the values of the neighbors:
        int valueLeftNeighbor = cells[(length - index - 1) % length].value,
            valueRightNeighbor = cells[(index + 1) % length].value,
        // And create an increment-integer with default value 0:
            increment = 0;
        // If the current value is smaller than that of both neighbors:
        if(value < valueLeftNeighbor && value < valueRightNeighbor){
          // Increase the current value by 1
          increment = 1;
        }
        // If the current value is larger than that of both neighbors:
        if(value > valueLeftNeighbor && value > valueRightNeighbor){
          // Decrease the current value by 1
          increment = -1;
        }
        // If the current value is smaller than or equal to one neighbor,
        // and larger than or equal to the other neighbor:
        //  Leave the value the same (so increment stays 0)

        // Wait until every cell is done calculating its new value:
        barrier.await();

        // And then actually update the values of the cells
        value += increment;
      }catch(Exception ex){
        System.err.println("Exception occurred! " + ex);
        ex.printStackTrace();
      }
    }

    @Override
    public String toString(){
      return Integer.toString(value);
    }
  }
}

基于this SO question and answerits accepted answer

我上面的代码目前做了什么:

它使用随机值amountOfCycles + 1 次打印数组,但不会在周期之间更改任何值。这是由于我得到的IllegalMonitorStateExceptions。可能是因为我在某处需要synchronized(barrier){ ... },因为barrierMain 类中而不是Cell?但是,将其添加到 Cell 类的 run 方法会导致程序不再打印任何内容,也不会终止..

Here in my code above in an online compilers to see the current (incorrect) result.

我期望它做什么:

每次循环后修改数组中的值。

【问题讨论】:

    标签: java multithreading async-await neighbours cyclicbarrier


    【解决方案1】:

    让我们回顾一下你的推理:

    问题 1

    为了在任何对象上调用 wait(),当前线程必须拥有它的监视器。您正在调用没有任何同步(障碍)的 barrier.wait()。

    这就是你得到IllegalMonitorStateException的原因

    问题 2

    添加同步部分会导致程序挂起,因为您没有创建任何线程。在 Runnable 上调用 run 会在同一个线程中同步执行它。没有其他线程可以调用notify

    问题 3

    您可能不想拨打Object.wait,而是拨打CyclicBarrier.await()。因此,Object.wait() 要求的同步讨论不是所需解决方案的一部分,我添加它只是为了澄清。

    【讨论】:

      【解决方案2】:

      有一些问题。

      1) 您没有创建线程。您可以像这样从 Runnable 创建线程:

      Thread t = new Thread(runnable); //create thread
      t.start(); //start the thread
      

      更改您的代码:

      for(int i=0; i<length; i++)
        cells[i].run();
      

      这样的:

      for (int i = 0; i < length; i++)
        new Thread(cells[i]).start();
      

      2)您不会在每个循环后打印数组,实际上您没有实现任何循环来产生循环。要在每个循环创建新的 Runnable 后打印数组,当所有线程到达循环屏障时将调用该数组,您可以直接将此 Runnable 设置为循环屏障

      所以更改您的代码:

      Scanner stdin = new Scanner(System.in);
      length = stdin.nextInt();
      amountOfCycles = stdin.nextInt();
      barrier = new CyclicBarrier(length);
      cells = new Cell[length];
      for(int i=0; i<length; i++)
        cells[i] = new Cell(i);
      

      这样的:

      Scanner stdin = new Scanner(System.in);
      length = stdin.nextInt();
      amountOfCycles = stdin.nextInt();
      
      cells = new Cell[length];
      for (int i = 0; i < length; i++)
        cells[i] = new Cell(i);
      
      barrier = new CyclicBarrier(length, () -> {
        System.out.println(Arrays.toString(cells)); //code that will run every time when all thread reach the cyclic barrier
      });
      

      3) 在线程中创建循环:

      更改您的代码:

      try{
        // Wait for the start of the cycle:
        barrier.wait(); //remove this, you never called notify so its useless
      
        //business logic omitted
      
        // Wait until every cell is done calculating its new value:
        barrier.await();
      
        // And then actually update the values of the cells
        value += increment;
      }catch(Exception ex){
        System.err.println("Exception occurred! " + ex);
        ex.printStackTrace();
      }
      

      这样的:

      int cycleCounter = 0;
      while (cycleCounter < amountOfCycles) {
        cycleCounter++;
        try {
          //business logic omitted
      
          barrier.await();
      
          // And then actually update the values of the cells    
          value += increment;
        } catch (Exception ex) {
          System.err.println("Exception occurred! " + ex);
          ex.printStackTrace();
        }
      }
      

      【讨论】:

      • 完美,非常感谢。现在一切都按预期工作。并感谢添加的 cmets 和解释。现在更有意义了。
      猜你喜欢
      • 2016-11-04
      • 1970-01-01
      • 2018-12-17
      • 1970-01-01
      • 2014-06-11
      • 1970-01-01
      • 2018-04-11
      • 1970-01-01
      • 2014-06-22
      相关资源
      最近更新 更多