【问题标题】:Java - How to limit the number of threads running at once when creating them in a for loopJava - 在 for 循环中创建线程时如何限制一次运行的线程数
【发布时间】:2014-12-28 04:42:46
【问题描述】:

我正在制作一个代理检查器,我已经制作了一个前一个,它是多线程的,但它为每个代理创建了一个新线程来检查,这就是我对这个做的,但是当我去使用它时检查 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();
}

我目前没有想法,所以任何帮助都会很棒。

【问题讨论】:

  • 为什么不从 for 循环中删除 &amp;&amp; runningThreads &lt;= 5 并在循环中添加一个 if 而不是 if (runningThreads &lt;= 5) { make a new thread }?如果你创建了一个线程,那么只增加i
  • 为什么不使用固定的线程池呢?此外,如果该进度条是一个 Swing JProgressBar,那么您的代码会通过对 EDT 进行 Swing 调用来忽略 Swing 线程规则。这可能会导致间歇性但有害的程序停止异常。

标签: java multithreading limit


【解决方案1】:

你可以使用这样的东西:

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 个“许可”,这意味着对 s.acquire() 的前 5 次调用将立即成功。但在那之后,s.acquire() 必须有对应的s.release() 才能成功。许可数量在每个线程开始之前减少一 (s.acquire()),并在每个线程退出之前备份一 (s.release())。由于 permit 的数量永远不能为负数,因此已启动但尚未退出的线程数永远不能超过 5。

您也可以使用Executors.newFixedThreadPool(5) 显式创建大小为 5 的线程池。如果任务数量非常大,那么使用线程池您必须考虑限制可以排队的任务数量,也许使用ThreadPoolExecutor。上面带有信号量的解决方案没有这个问题,因为它没有排队任何东西。

【讨论】:

    【解决方案2】:

    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();
    

    【讨论】:

      【解决方案3】:

      您可以将 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 时创建新线程。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多