簡體   English   中英

Java多線程優化

[英]Multithreading java optimization

在我的程序中,我嘗試了解如何使用ExecutorService優化程序。 由於某些原因,它在兩個Urls上卡住了一點。 http://sjsu.edu/https://paypal.com 當位於這兩個位置上時,它不會繼續執行其他URL。

即使兩個域的響應速度不夠快,其他三個可用線程是否也不應繼續運行?

如何以最佳方式解決此問題?

public class SequentialPinger {
    public static void main(String args[]) throws Exception {

        String[] hostList = {"http://crunchify.com", "http://yahoo.com",
            "http://www.ebay.com", "http://google.com",
            "http://www.example.co", "https://paypal.com",
            "http://bing.com/", "http://techcrunch.com/",
            "http://mashable.com/", "http://thenextweb.com/",
            "http://wordpress.com/", "http://cphbusiness.dk/",
            "http://example.com/", "http://sjsu.edu/",
            "http://ebay.co.uk/", "http://google.co.uk/",
            "http://www.wikipedia.org/",
            "http://dr.dk", "http://pol.dk", "https://www.google.dk",
            "http://phoronix.com", "http://www.webupd8.org/",
            "https://studypoint-plaul.rhcloud.com/", "http://stackoverflow.com",
            "http://docs.oracle.com", "https://fronter.com",
            "http://imgur.com/", "http://www.imagemagick.org"
        };

        List<CallableImpl> callList = new ArrayList();
        ExecutorService es = Executors.newFixedThreadPool(4);

        for (String url : hostList) {
            CallableImpl callable = new CallableImpl(url);
            callList.add(callable);
        }
        for (CallableImpl callableImpl : callList) {
            System.out.println("Trying to connect to: " + callableImpl.getUrl());
            Future<String> lol = es.submit(callableImpl);
            System.out.println("status: " + lol.get());
        }

        es.shutdown();

    }
}

我的Callable實現

public class CallableImpl implements Callable<String> {

    private final String url;

    public CallableImpl(String url) {
        this.url = url;
    }

    public String getUrl() {
        return url;
    }

    @Override
    public String call() {
        String result = "Error";

        try {
            URL siteURL = new URL(url);
            HttpURLConnection connection = (HttpURLConnection) siteURL
                    .openConnection();
            connection.setRequestMethod("GET");

            connection.connect();

            int code = connection.getResponseCode();
            if (code == 200) {
                result = "Green";
            }

            if (code == 301) {
                result = "Redirect";
            }

        } catch (IOException e) {
            result = "->Red<-";
        }
        return result;
    }
}

在您的代碼中,將Callable Future.get()提交給ExecutorService ,然后立即調用Future.get() ,它將阻塞直到結果准備好(或在運行時引發異常)。

您最好將ExecutorServiceCompletionSerivce包裝在一起,后者可以在准備好結果后立即提供結果。 並將for循環分為兩個循環:一個循環提交所有Callable ,第二個循環檢查結果。

ExecutorService es = Executors.newFixedThreadPool(4);
ExecutorCompletionService<String> completionService = new ExecutorCompletionService<>(es);

for (CallableImpl callableImpl : callList) {
        System.out.println("Trying to connect to: " + callableImpl.getUrl());
        completionService.submit(callableImpl);
}
for (int i = 0; i < callList.size(); ++i) {
    completionService.take().get();   //fetch next finished Future and check its result
}

問題

創建后,您get()Future直接調用get() ,從而阻塞主線程。 因此,您根本沒有任何並行調用,這使ExecutorService本質上無用。 您的代碼等效於自己簡單地調用callableImpl.call()

如果要繼續執行並讓每個CallableImpl並行運行,請不要調用get() 相反,您可以在es.awaitTermination()之后調用es.shutdown()

我建議使用Java 8中添加的CompletableFuture並為其添加回調。

CompletableFuture.supplyAsync(myCallable::call, es)
        .thenAccept(result -> {
            something(result);
        });

我建議您將Callable變成供應商,以簡化此過程。

您寫道:“它不會繼續執行其他URL”-我相信它會執行,但是您的日志消息具有誤導性,因為它與實際執行沒有緊密聯系。 要解決此問題,請執行以下操作:

  1. System.out.println("Trying to connect to: ")System.out.println("status: ")移到CallableImpl.call()方法中。
  2. 根本不要調用lol.get()

這樣,您將看到處理每個URL的開始和結束的實際順序。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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