Java - Как ограничить количество одновременно работающих потоков при их создании в цикле for

1

Я делаю проверку прокси, и я сделал предыдущий, и он был многопоточным, но он создал новый поток для каждого прокси, чтобы проверить, что я делал с этим, но когда я пошел использовать его для проверки прокси-серверов 60k он чуть не растаял мой компьютер. Я пытался ограничить количество потоков, запущенных сразу, но не повезло. То, как я изначально делал это, было так

for(int i = 0; i < proxies.size(); i++){
    final String s = proxies.get(i);
    new Thread(){
        public void run(){
            Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(s.split(":")[0], Integer.parseInt(s.split(":")[1])));
            if(checkProxy(proxy, 5000))
                textArea_1.setText(textArea_1.getText() + s + "\n");
            progress++;
            progressBar.setValue(progress);
        }
    }.start();
}

То, как я пытался ограничить, - это иметь глобальную переменную, которая увеличивалась для каждого нового потока, а затем уменьшалась сама по себе для конца каждого нового потока, считая, что цикл остановится и дождитесь, пока переменная будет достаточно низкой, чтобы создать новый поток, подобный

for(int i = 0; i < proxies.size() && runningThreads <= 5; i++){
    runningThreads++;
    final String s = proxies.get(i);
    new Thread(){
        public void run(){
            Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(s.split(":")[0], Integer.parseInt(s.split(":")[1])));
            if(checkProxy(proxy, 5000))
                textArea_1.setText(textArea_1.getText() + s + "\n");
            progress++;
            progressBar.setValue(progress);
            runningThreads--;
        }
    }.start();
}

В настоящее время у меня нет идей, поэтому любая помощь будет отличной.

  • 0
    Почему бы не удалить && runningThreads <= 5 из цикла for и просто if (runningThreads <= 5) { make a new thread } в цикл if (runningThreads <= 5) { make a new thread } вместо if (runningThreads <= 5) { make a new thread } ? Тогда только увеличивайте i если вы создаете поток.
  • 2
    Почему бы не использовать фиксированный пул потоков? Кроме того, если индикатор выполнения представляет собой Swing JProgressBar, то ваш код игнорирует правила потоков Swing, вызывая вызовы Swing из EDT. Это может привести к прерывистым, но пагубным исключениям, ограничивающим программы.
Теги:
multithreading
limit

3 ответа

5

Вы можете использовать что-то вроде этого:

Semaphore s = new Semaphore(5);
for (int i = 0; i < proxies.size(); i++) {
  s.acquire();
  new Thread() {
    public void run() {
      try {
        ...proxy stuff...
      } finally {
        s.release();
      }
    }
  }.start();
}

Семафор имеет 5 "разрешений", что означает, что первые 5 вызовов s.acquire() будут немедленно выполнены. Но после этого s.acquire() может быть успешным только в том случае, если была соответствующая s.release(). Количество разрешений уменьшается на один (s.acquire()) перед началом каждого потока и создается резервным копированием одним (s.release()) перед каждым выходом потока. Поскольку количество разрешений никогда не может быть отрицательным, количество потоков, которые начались, но еще не вышло, никогда не может превышать 5.

Вы также можете использовать Executors.newFixedThreadPool(5), чтобы явно создать пул потоков размером 5. Если количество задач может быть действительно большим, то с пулами потоков вам нужно подумать об ограничении числа задач, которые могут быть поставлены в очередь, возможно используя ThreadPoolExecutor. Вышеупомянутое решение с семафорами не имеет этой проблемы, потому что оно ничего не ставит в очередь.

1

Hovercraft Full Of Eels ответил на этот вопрос с помощью FixedThreadPool, я не знаю, как сделать комментарий, поэтому я просто ответил сам себе и дал ему кредиты. Я только что создал класс, который расширил Thread и поместил свой проверочный код прокси в метод run() класса, а затем, где мой старый код был заменен на него.

ExecutorService executor = Executors.newFixedThreadPool(Integer.parseInt(textField.getText()));
for(int i = 0; i < proxies.size(); i++){
    final String s = proxies.get(i);
    Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(s.split(":")[0], Integer.parseInt(s.split(":")[1])));
    Thread thread = new CheckThread(proxy, 5000, i);
    executor.execute(thread);
}
executor.shutdown();
0

Вы можете изменить цикл for на цикл while.

while (true) {
    while (runningThreads <= 5) {
        runningThreads++;
        final String s = proxies.get(i);
        new Thread(){
            public void run(){
                Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(s.split(":")[0], Integer.parseInt(s.split(":")[1])));
                if(checkProxy(proxy, 5000))
                    textArea_1.setText(textArea_1.getText() + s + "\n");
                progress++;
                progressBar.setValue(progress);
                runningThreads--;
            }
        }.start();
    }

    Thread.sleep(100);
}

Внешний цикл while (true) будет продолжать проверку и создавать новые потоки, если текущие потоки опускаются ниже 5.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню