java - 如何使用 CyclingBarrier 同步线程并保持它们的执行顺序?
问题描述
我想编写一个多线程应用程序,逐个打印字符串中的字符,并在第一个“回合”之后保留其他回合的顺序。它应该像这样工作:
对于字符串:
private String[] strings = {"aaaa", "bb", "ccccccccccccc", "dddddd"};
它会打印:
abcd abcd acd acd cd cd c c c c c c c
或者可能
dbac dbac dac dac dc dc c c c c c c c
取决于在第一轮中首先开始的过程
到目前为止,我的解决方案看起来像这样
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
public class Printer {
private CyclicBarrier cyclicBarrier;
private final static String one = "aaa";
private final static String two = "bbbb";
private final static String three = "c";
private final static String four = "dddddd";
public static void main(String[] args) {
Printer printer = new Printer();
printer.runSimulation(4);
}
private void runSimulation(int numberOfStrings) {
cyclicBarrier = new CyclicBarrier(numberOfStrings, new AggregatorThread());
Thread thread = new Thread(new PrintingThread(padSpaces(one, 10)));
Thread thread1 = new Thread(new PrintingThread(padSpaces(two, 10)));
Thread thread3 = new Thread(new PrintingThread(padSpaces(three, 10)));
Thread thread4 = new Thread(new PrintingThread(padSpaces(four, 10)));
thread.start();
thread1.start();
thread3.start();
thread4.start();
}
class AggregatorThread implements Runnable{
@Override
public void run() {
System.out.print(" ");
}
}
class PrintingThread implements Runnable{
private String toPrint;
private int iterator;
public PrintingThread(String toPrint) {
this.toPrint = toPrint;
this.iterator = 0;
}
@Override
public void run() {
while(iterator < toPrint.length()) {
System.out.print(toPrint.charAt(iterator));
iterator++;
try {
cyclicBarrier.await();
} catch (InterruptedException | BrokenBarrierException e) {
e.printStackTrace();
}
}
}
}
private String padSpaces(String inputString, int length) {
if (inputString.length() >= length) {
return inputString;
}
StringBuilder sb = new StringBuilder();
while (sb.length() < length - inputString.length()) {
sb.append(' ');
}
StringBuilder sb1 = new StringBuilder(inputString);
sb1.append(sb);
return sb1.toString();
}
}
但它不保留写入控制台的字母顺序,而且我现在将字符串填充为一些硬编码值,但我想让它在没有相等字符串的情况下正常工作。对此有何建议?
解决方案
既然您要求使用 的解决方案CyclicBarrier
,这里有一种方法可以用一个来做到这一点......但我绝对不会首先想到如何解决这个问题(假设问题不是“用CyclicBarrier
'...)。
- 创建一个
CyclicBarrier
长度为 4 的。 - 在开始时(使用 an或其他方式)为每个人分配
Thread
一个数字(0 到 3)。AtomicInteger
让每个人都
Thread
做类似的事情:while (barrier.getNumberWaiting() != this.threadNumber) { } // Do your adding to the StringBuilder here... barrier.await();
即每个Thread
旋转直到等待方的数量等于那个Thread
数量。
分配为 0 的总是先通过,而其他所有的都卡在旋转中。一旦它Thread
完成了它StringBuilder
的事情,它就会await
,这反过来又释放了Thread
分配的 1 去通过。编号分配后顺序将保持一致。
要获取每个进程的唯一 ID,AtomicInteger
可以使用简单的。
private final AtomicInteger idCounter = new AtomicInteger();
private final CyclicBarrier barrier = new CyclicBarrier(4);
private final AtomicInteger doneCounter = new AtomicInteger();
public Runnable createRunnable() {
return () -> {
final int threadId = this.idCounter.getAndIncrement();
boolean threadDone = false;
boolean moreCharacters = true;
while (true) {
while (this.barrier.getNumberWaiting() != threadId) {
}
// Add to StringBuilder here...
// Set the 'moreCharacters' flag as false once this thread
// has handled its String.
// They will still need to spin though, to make sure the
// parties waiting keep adding up as appropriate.
if (!moreCharacters && !threadDone) {
// 'threadDone' used so that each thread only
// increments the 'doneCounter' once.
this.doneCounter.incrementAndGet();
threadDone = true;
}
barrier.await();
if (this.doneCounter.get() == 4) {
// Exit out of the loop once all Threads are done.
break;
}
}
};
}
推荐阅读
- python - 带有 2D numpy 数组输入的 Tensorflow Keras Conv2D 错误
- ios - 用于更改标签文本的 Swift 按钮操作不起作用
- php - User.php boot() 方法在用户注册时被多次调用
- mysql - 如果所选日期没有可用数据,则查询打印 null
- java - 如何从另一个活动访问抽屉
- javascript - 通过查询或从 Vue 中的存储发送数据
- r - 使用 R 选择具有最高值的列
- javascript - Chrome 扩展程序如何“侦听”主机页面上的所有 iFrame 以完成加载?
- mongodb - MongoDB 喜欢(upvote)和不喜欢(downvote)模式设计
- javascript - 带有渐变的 SVG 圆形颜色