我可以在队列中并行化长时间运行的任务而不会创建太多线程

时间:2014-04-16 21:40:14

标签: java multithreading

我有一个带有250个条目的队列的线程池,每秒我都会推送每60个任务。通常,任务运行得非常快,但如果某些条件满足,则需要执行长时间运行的任务。正常任务运行现在被阻止,因为正在执行长时间运行的任务。

执行时间是否可以分割一个Runnable的执行(在需要长时间运行的任务的情况下)
  1. 正常任务
  2. 长时间运行的任务
  3. 换句话说:我喜欢异步启动长时间运行的任务,但我不想创建太多的线程,因为在那种情况下我会因为线程通信而得到开销。我可以使用ForkJoinPool吗?还是我必须分开长期和短期运行任务来解决这个问题?

    我的机器有4个核心:

    ExecutorService queue = new ThreadPoolExecutor(2,
                4,
                400,
                TimeUnit.MILLISECONDS,
                new ArrayBlockingQueue<Runnable>(250, true),
                new ThreadPoolExecutor.DiscardOldestPolicy());
        Runnable r = new Runnable() {
            @Override
            public void run() {
                try {
                   if(isTimeForLongRunningExecution()){
                        //Is it possible to start this job asynchronous without starting to many threads
                        doLongRunningTask();
                    }//do job with old data until new data is available, but do not block this operation too long
                    doNormalTaskWithOldOrNewData();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
    
            private void doNormalTaskWithOldOrNewData() throws InterruptedException {
                if(checkNewDataAvailable()){
                   System.out.println("Work with new Data");
                   Thread.sleep(300L);
                   System.out.println("Work completed!");
                }else{ 
                  System.out.println("Work with old Data");
                  Thread.sleep(300L);
                  System.out.println("Work completed!");
                }
            }
    
            private void doLongRunningTask() throws InterruptedException {
                  System.out.println("Create new Data");
                  Thread.sleep(3*60*1000L);
                  System.out.println("Data creation completed!");
            }
        };//end of runnable
    
        while(true){
            for (int i = 0; i < 60; i++) {
                queue.submit(r);
            }
            Thread.sleep(1000);
        }
    

3 个答案:

答案 0 :(得分:0)

这是一项有趣的任务,但我并不了解你想要达到的目标。你正在给出一个解决方案,但你没有告诉我们问题是什么,因为这里有很多人可以建议你一个更合适的解决方案。

无论如何,我建议您下载并使用VisualVM

如果您尚未使用它,请监控性能并查看延迟的位置。在过去,我发现理解线程在哪里等待非常有用(你有同步代码吗?)。

为什么不尝试在与Normal任务分开的Thread中启动长时间运行的任务? 另请查看Executors.newCachedThreadPool(),因为执行许多short-lived asynchronous tasks非常好。

最后,如果你还没有这样做,我还建议给性能计时并看看自己如何改善/变得更糟,或者使用其他一些指标(将普通线程读取新数据的次数存储在某处) ,旧数据)。

答案 1 :(得分:0)

使用2 ordinary thread pools - 一个用于快速,另一个用于长时间运行的任务。让每个线程池拥有与处理器核心一样多的线程。将所有任务提交到快速线程池。让任务,如果它发现需要长时间工作,则将另一个任务提交给长线程池并退出。

答案 2 :(得分:0)

我想到的最简单的解决方案是使用两个队列。其中一个是短期生活任务,一个是长期生活任务的无限期。

您也可以使用自己的线程创建例程构造Executor,并确保所有这些长生命线程都以低优先级运行,因此它们不会干扰短期任务。

final Executor longLivingTasksExecutor = Executors.newCachedThreadPool(new PriorityThreadFactory(Thread.MIN_PRIORITY));

PriorityThreadFactory是我自己写的课程:

public class PriorityThreadFactory implements ThreadFactory, ForkJoinPool.ForkJoinWorkerThreadFactory {

  protected final ThreadGroup allThreads;
  protected final int priority;

  public PriorityThreadFactory(final String name, final int priority, final boolean daemon) {
    this.priority = priority;
    this.allThreads = new ThreadGroup(name);
    this.allThreads.setMaxPriority(priority);
    this.allThreads.setDaemon(daemon);
  }

  public PriorityThreadFactory(final int priority, final boolean daemon) {
    this("workers", priority, daemon);
  }

  public PriorityThreadFactory(final int priority) {
    this("workers", priority, false);
  }

  @Override
  public Thread newThread(final Runnable r) {
    return new Thread(this.allThreads, r);
  }

  @Override
  public ForkJoinWorkerThread newThread(final ForkJoinPool pool) {
    final ForkJoinWorkerThread result = ForkJoinPool.defaultForkJoinWorkerThreadFactory.newThread(pool);
    result.setPriority(priority);
    return result;
  }
}