简体   繁体   English

Java中的线程等待列表

[英]Waiting list of threads in java

I'm writing a swing application with HttpClient and I need a way to make a download list because I need to wait 1 minute (for example) before starting a new download. 我正在用HttpClient编写一个swing应用程序,并且需要一种下载列表的方法,因为在开始新的下载之前,我需要等待1分钟(例如)。

So I would like to create a waiting list of threads (downloads). 因此,我想创建一个线程等待列表(下载)。 I would have a class that takes a time parameter and contains a list of threads and when I add a thread in the list it starts if there is no running thread. 我会有一个带有时间参数并包含线程列表的类,当我在列表中添加线程时,如果没有正在运行的线程,它将开始。 Otherwise it waits for its turn. 否则,它等待轮到它。

Is there any tool to do that ? 有什么工具可以做到这一点吗?

Thanks a lot for your help. 非常感谢你的帮助。

Yes. 是。 ScheduledExecutorService . ScheduledExecutorService You can create a fixed length service via Executors.newScheduledThreadPool(corePoolSize) . 您可以通过Executors.newScheduledThreadPool(corePoolSize)创建固定长度的服务。 When you are ready to submit the task to wait the amount of time just submit it to ScheduledExecutorService.schedule 当您准备提交任务以等待一段时间时,只需将其提交给ScheduledExecutorService.schedule

ScheduledExecutorService e = Executors.newScheduledThreadPool(10)
private final long defaultWaitTimeInMinutes = 1;
public void submitTaskToWait(Runnable r){
    e.schedule(r, defaultWaitTimeInMinutes, TimeUnit.MINUTES);
}

Here the task will launch in 1 minute from the time of being submitted. 在这里,任务将在提交后的1分钟内启动。 And to address your last point. 并解决您的最后一点。 If there are currently tasks being downloaded (this configuration means 10 tasks being downloaded) after the 1 minute is up the runnable submitted will have to wait until one of the other downloads are complete. 如果在1分钟后当前有正在下载的任务(此配置意味着要下载10个任务),则可运行的提交将不得不等待,直到其他下载之一完成。

Keep in mind this deviates a bit from the way you are designing it. 请记住,这与您的设计方式有所不同。 For each new task you wouldnt create a new thread, rather you would submit to a service that already has thread(s) waiting. 对于每个新任务,您都不会创建一个新线程,而是会提交给已经有线程等待的服务。 For instance, if you only want one task to download at a time you change from Executors.newScheduledThreadPool(10) to Executors.newScheduledThreadPool(1) 例如,如果您一次只希望下载一个任务,则从Executors.newScheduledThreadPool(10)更改为Executors.newScheduledThreadPool(1)

Edit: I'll leave my previous answer but update it with a solution to submit a task to start exactly 1 minute after the previous task completes. 编辑:我将保留上一个答案,但使用解决方案对其进行更新,以提交任务以在上一个任务完成后1分钟恰好开始。 You would use two ExecutorServices. 您将使用两个ExecutorServices。 One to submit to the scheuled Executor and the other to do the timed executions. 一个提交给被规避的执行人,另一个执行定时执行。 Finally the first Executor will wait on the completion and continue with the other tasks queued up. 最后,第一个执行程序将等待完成,并继续排​​队等待其他任务。

ExecutorService e = Executors.newSingleThreadExecutor();
ScheduledExecutorService scheduledService = Executors.newScheduledThreadPool(1)
public void submitTask(final Runnable r){
    e.submit(new Runnable(){
       public void run(){
           ScheduledFuture<?> future= scheduledService.schedule(r, defaultWaitTimeInMinutes, TimeUnit.MINUTES);
           future.get(); 

       }
    });
}

Now when the future.get(); 现在,当future.get(); completes the next Runnable submitted through submitTask will be run and then scheduled for a minute. 完成后,将运行通过SubmitTask提交的下一个Runnable,然后安排一分钟。 Finally this will work only if you require the task to wait the 1 minute even if there is no other tasks submitted. 最后,仅当您要求任务等待1分钟(即使没有其他任务提交)时,此方法才起作用。

I think this would be a wrong way of going about the problem. 我认为这是解决该问题的错误方法。 A bit more logical way would be to create "download job" objects which will be added to a job queue. 更具逻辑性的方式是创建“下载作业”对象,该对象将添加到作业队列中。 Create a TimerTask which would query this "queue" every 1 minute, pick up the Runnable / Callable jobs and submit them to the ExecutorService . 创建一个TimerTask ,它将每1分钟查询一次此“队列”,选择Runnable / Callable作业,并将其提交给ExecutorService

You could use the built-in ExecutorService . 您可以使用内置的ExecutorService You can queue up tasks as Runnable s and they will run on the available threads. 您可以将任务作为Runnable排队,它们将在可用线程上运行。 If you want only a single task to run at a time use newFixedThreadPool(1); 如果您一次只希望运行一个任务,请使用newFixedThreadPool(1);

ExecutorService executor = Executors.newFixedThreadPool(1);

You could then append an artificial Thread.sleep at the beginning of each Runnable run method to ensure that it waits the necessary amount of time before starting (not the most elegant choice, I know). 然后,您可以在每个Runnable run方法的开头附加一个人造Thread.sleep ,以确保它在启动之前等待必要的时间(我知道这不是最优雅的选择)。

The Java Concurrency package contains classes for doing what you ask. Java并发包包含用于执行您所要求的类的类。 The general construct you're talking about is an Executor which is backed by a ThreadPool. 您正在谈论的一般构造是由ThreadPool支持的Executor You generate a list of Runables and send them to an Executor. 您将生成可运行项列表,并将其发送给执行程序。 The Executor has a ThreadPool behind it which will run the Runnables as the threads become available. 执行程序后面有一个线程池,当线程可用时,它将运行Runnables。

So as an example here, you could have a Runnable like: 因此,这里有一个示例,您可以使用类似Runnable

  private static class Downloader implements Runnable {

    private String file;

    public Downloader(String file) {
      this.file = file;
    }

    @Override
    public void run() {
      // Use HttpClient to download file.
    }
  }

Then You can use it by creating Downloader objects and submitting it to an ExecutorService: 然后,可以通过创建Downloader对象并将其提交到ExecutorService来使用它:

  public static void main(String[] args) throws Exception {
    ExecutorService executorService = Executors.newFixedThreadPool(5);
    for (String file : args) {
      executorService.submit(new Downloader(file));
    }
    executorService.awaitTermination(100, TimeUnit.SECONDS);
  }

It is maybe not the best solution but here is what I came up with thanks to the answer of John Vint. 这可能不是最好的解决方案,但是由于John Vint的回答,这就是我的想法。 I hope it will help someone else. 我希望它会帮助别人。

package tests;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;


public class RunnableQueue 
{
    private long waitTime;
    private TimeUnit unit;

    ExecutorService e;

    public RunnableQueue(long waitTime, TimeUnit unit) {
        e = Executors.newSingleThreadExecutor();

        this.waitTime = waitTime;
        this.unit = unit;
    }

    public void submitTask(final Runnable r){
        e.submit(new Runnable(){
           public void run(){
               Thread t = new Thread(r);
               t.start();

               try {
                t.join();
                Thread.sleep(unit.toMillis(waitTime));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
           }
        });
    }

    public static void main(String[] args) {
        RunnableQueue runQueue = new RunnableQueue(3, TimeUnit.SECONDS);

        for(int i=1; i<11; i++)
        {
            runQueue.submitTask(new DownloadTask(i));
            System.out.println("Submitted task " + i);
        }

    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM