[英]Stopping all threads when one of them is finished
目標是創建搜索方法,該方法返回在所有搜索線程中首先找到的針的索引。 當其中之一完成時,我需要停止所有線程。
邏輯是:有4個線程。 第一個線程檢查干草堆的第一個%25,第二個線程檢查干草堆的%25-%50,依此類推。
一旦其中一個打印了文本,我就應該停止,但是我總是得到4個輸出,因為所有4個都在大海撈針中找到針頭。 但是,我只需要一個輸出。
示例輸出:(下面的索引)
I found, it is: 622
I found, it is: 4072
I found, it is: 7519
I found, it is: 7264
這是擴展線程的SearcherThreat類
public class SearcherThread extends Thread {
// PROPERTIES
private int needle;
private int[] haystack;
private int start, end;
// CONSTRUCTOR
public SearcherThread(int needle, int[] haystack, int start, int end) {
this.needle = needle;
this.haystack = haystack;
this.start = start;
this.end = end;
}
@Override
public void run() {
for (int i = start; i < end && !isInterrupted(); ++i) {
if (haystack[i] == needle) {
System.out.println("I found, it is: " + i);
for (SearcherThread searcher : InterruptTest.searchers) {
searcher.interrupt();
}
}
}
}
}
這是包含主線程和線程的類
import java.util.ArrayList;
public class InterruptTest {
public static ArrayList<SearcherThread> searchers = new ArrayList<SearcherThread>();
public static void main(String[] args) throws InterruptedException {
int itemCount = 10000;
int[] haystack = new int[itemCount];
int domainSize = 1000;
for (int i = 0; i < itemCount; ++i)
haystack[i] = (int) (Math.random() * domainSize);
int needle = 10;
int numThreads = 4;
int numItemsPerThread = haystack.length / numThreads;
int extraItems = haystack.length - numItemsPerThread * numThreads;
for (int i = 0, start = 0; i < numThreads; ++i) {
int numItems = (i < extraItems) ? (numItemsPerThread + 1) : numItemsPerThread;
searchers.add(new SearcherThread(needle, haystack, start, start + numItems));
start += numItems;
}
for (SearcherThread searcher : searchers)
searcher.start();
}
}
我得到以下輸出:
[stephen@blackbox tmp]$ java InterruptTest
I found, it is: 855
I found, it is: 3051
[stephen@blackbox tmp]$ java InterruptTest
I found, it is: 2875
I found, it is: 5008
I found, it is: 1081
I found, it is: 8527
[stephen@blackbox tmp]$ java InterruptTest
I found, it is: 2653
I found, it is: 5377
I found, it is: 1092
[stephen@blackbox tmp]$ java InterruptTest
I found, it is: 255
I found, it is: 9095
I found, it is: 6983
I found, it is: 3777
如您所見, 從一次運行到下一次運行,完成的線程數有所不同 。
我們這里是一場比賽。 可能發生的情況是,一個線程在啟動之前完成並中斷了其他線程。 因此他們看不到中斷。 Javadoc說:
“中斷未激活的線程不會產生任何效果。”
另一個可能性是中斷傳播的速度不夠快。 請注意,javadoc並未說被中斷的線程可以立即看到一個interrupt()
。
我想不出一個解決方案,它不會否定多線程帶來的好處。 另一方面,在實際的用例中:
如果您測量了當前測試中獲得的實際加速,則可能為負 。
總而言之,在更實際的測試中,您應該大多數時候都看到中斷起作用。 那應該足夠了。 (沒關系,有時線程的中斷速度不足以阻止它們找到次要結果。)
這是壞事,但這可以幫助其他人。 您可以使用Java內置的Executors 。 使用Java 8,它具有
這是一個有關如何編寫類的示例。 我正在使用newFixedThreadPool(int nThreads)來匹配您在代碼中所做的事情
import java.util.concurrent.Callable;
public class SearcherThread implements Callable<Object> {
// PROPERTIES
private int needle;
private int[] haystack;
private int start, end;
// CONSTRUCTOR
public SearcherThread(int needle, int[] haystack, int start, int end) {
this.needle = needle;
this.haystack = haystack;
this.start = start;
this.end = end;
}
@Override
public Object call() throws Exception {
for (int i = start; i < end ; ++i) {
if (haystack[i] == needle) {
return i;
}
}
Thread.sleep(5000);
return null;
}
}
和測試班
import java.util.ArrayList;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class InterruptTest {
public static ArrayList<SearcherThread> searchers = new ArrayList<SearcherThread>();
public static void main(String[] args) throws InterruptedException, ExecutionException {
int itemCount = 10000;
int[] haystack = new int[itemCount];
int domainSize = 1000;
for (int i = 0; i < itemCount; ++i)
haystack[i] = (int) (Math.random() * domainSize);
int needle = 10;
int numThreads = 4;
int numItemsPerThread = haystack.length / numThreads;
int extraItems = haystack.length - numItemsPerThread * numThreads;
for (int i = 0, start = 0; i < numThreads; ++i) {
int numItems = (i < extraItems) ? (numItemsPerThread + 1) : numItemsPerThread;
searchers.add(new SearcherThread(needle, haystack, start, start + numItems));
start += numItems;
}
//Preferred to use Executors.newWorkStealingPool() instead
ExecutorService executor = Executors.newFixedThreadPool(numThreads);
executor.shutdown();//shutdown when done
Object result = executor.invokeAny(searchers);//<------- right here lookie
System.out.println("I found, it is: "+result);
}
}
ExecutorService.invokeAny(List <Callable>)將運行所有可調用線程並獲取第一個完成線程的值。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.