根据相邻节点的值更新多线程单元。如何继续使用CyclicBarrier?



我正在尝试完成以下任务:

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

根据其邻居更新这些值是多线程的原因。请注意,这只是练习多线程的东西。我可以轻松地完成上述操作,只需将所有线程一起删除并创建数组的副本(我已经这样做了)。

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

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);
}
}
}

这是基于这个SO问题和答案及其公认的答案。

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

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

在我上面的代码中,在在线编译器中查看当前(不正确)的结果。

我希望它做什么:

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

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

问题 1

为了在任何对象上调用wait(),当前线程必须拥有其监视器。你正在调用 barrier.wait() 而没有任何 syncd(barrier)。

这就是你得到IllegalMonitorStateException的原因

问题 2

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

问题 3

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

有几个问题。

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();
}
}

最新更新