我在執行以下任務時遇到了麻煩:
兩個執行緒都訪問類 Print 的物件,并以相反的順序逐個字母地列印變數型別 String 的值,其中每個字母都用連字符 (–) 列印。示例:輸入 = 名稱。輸出 = EEMMAANN。
我所做的如下:
public class Print implements Runnable {
private String string;
Print(String string) {
this.string = string;
}
@Override
public void run() {
// TODO Auto-generated method stub
for(int i = string.length()-1; i >= 0; i--) {
System.out.print(string.charAt(i) "-");
}
}
}
public class Task1 {
public static void main(String[] args) {
Print r = new Print("NAME");
Thread t1 = new Thread(r);
Thread t2 = new Thread(r);
t1.start();
t2.start();
}
}
它通常會列印 EMANEMAN,但可能會有所不同。如何確保它始終列印所需的結果?非常感謝
uj5u.com熱心網友回復:
正如我在評論中提到的,你需要CyclicBarrier,它將協調兩個執行緒,而不是讓一個或另一個運行。
但是,如果您不希望-列印最后一個字符,則需要在兩個執行緒之間進行另一個協調以用于i == 0. 一個執行緒將列印最后一個字母加一個-,然后通知另一個執行緒繼續列印最后一個字母。這可以通過一個原子變數和一個CountDownLatch. 誰贏得原子變數的更新將列印 letter-dash 并倒計時鎖存器,失敗者將等待鎖存器并列印字母。
class Print implements Runnable {
private String string;
private CyclicBarrier cb = new CyclicBarrier(2);
private CountDownLatch cdl = new CountDownLatch(1);
private AtomicBoolean win = new AtomicBoolean();
Print(String string) {
this.string = string;
}
@Override
public void run() {
try {
for (int i = string.length()-1; i >= 0; i--) {
cb.await();
if (i != 0) {
System.out.print(string.charAt(i) "-");
} else {
if (win.getAndSet(true)) {
cdl.await();
System.out.print(string.charAt(i));
} else {
System.out.print(string.charAt(i) "-");
cdl.countDown();
}
}
}
} catch (Throwable ex) {
ex.printStackTrace();
}
}
}
請注意,此設定僅適用于 2 個執行緒。
uj5u.com熱心網友回復:
它通常列印 EMANEMAN,但可能會有所不同。如何確保它始終列印所需的結果?
在不采取任何額外步驟的情況下,每次輸出都會有所不同。第一個執行緒 ( t1) 盡可能快地運行,并且該執行緒不知道可能還有其他PrintRunnable 實體。
為確保它始終列印所需的結果,您需要執行緒以某種方式進行協調。在高層次上,邏輯看起來像:
- 列印單個字母(給定輸入“NAME”,在第一次通過回圈時列印“E”)
- 等待所有其他執行緒也列印它們的字母——正確的方法是使用幾個內置同步選項之一
- 一旦所有執行緒都同意是時候繼續了,他們就可以繼續
如何進行的一些選項:使用CyclicBarrier或Phaser。
這是一個示例,展示了如何使用移相器解決此問題。
首先,這是每個執行緒的類。在建構式中,它接受 a Phaser、 a List<String>(每個執行緒將在其中添加輸出)和字串文本本身(例如:“NAME”)。
class CoordinatedRunnable implements Runnable {
private final Phaser phaser;
private final List<String> outputBuffer;
private final String text;
CoordinatedRunnable(Phaser phaser, List<String> output, String text) {
this.text = text;
this.phaser = phaser;
this.outputBuffer = output;
phaser.register();
new Thread(this).start();
}
@Override
public void run() {
for (int i = text.length() - 1; i >= 0; i--) {
outputBuffer.add(String.valueOf(text.charAt(i)));
phaser.arriveAndAwaitAdvance();
}
phaser.arriveAndDeregister();
}
}
這是呼叫者的代碼,使用文本“NAME”并創建由同一個移相器協調的 2 個執行緒。
Phaser phaser = new Phaser();
phaser.register();
List<String> outputBuffer = Collections.synchronizedList(new ArrayList<>());
String text = "NAME";
for (int i = 0; i < 2; i ) {
new CoordinatedRunnable(phaser, outputBuffer, text);
}
// main loop advances through each phase, along with each worker thread
for (int i = 0; i < text.length(); i ) {
phaser.arriveAndAwaitAdvance();
}
// reach here only when everyone is done with all phases
// print everything in the buffer, except for the last item
for (int i = 0; i < outputBuffer.size() - 1; i ) {
System.out.print(outputBuffer.get(i) "-");
}
// print the last item by itself, no delimiter
System.out.print(outputBuffer.get(outputBuffer.size() - 1));
這是輸出:
E-E-M-M-A-A-N-N
而且由于移相器是唯一的協調點,它也適用于超過 2 個執行緒。例如,這里是 10 個執行緒的輸出:
E-E-E-E-E-E-E-E-E-E-M-M-M-M-M-M-M-M-M-M-A-A-A-A-A-A-A-A-A-A-N-N-N-N-N-N-N-N-N-N
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/496633.html
上一篇:任務相互等待完成
