簡體   English   中英

當其中一個完成時停止所有線程

[英]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,它具有

  1. newCachedThreadPool()
  2. newFixedThreadPool(int nThreads)
  3. newSingleThreadExecutor()
  4. 等等

這是一個有關如何編寫類的示例。 我正在使用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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM