【问题标题】:Adding Thread in ThreadPool in Executor Service在Executor Service的ThreadPool中添加线程
【发布时间】:2013-03-05 17:56:52
【问题描述】:

我正在开发一个多线程程序,我试图确保每个线程都在为30 minutes 运行。假设如果我们有10 threads,那么10 之外的每个线程都应该为30 minutes 运行。

下面是我的代码-

class ThreadTask implements Runnable {
    private final long endTime;

    public ThreadTask(long endTime) {
        this.endTime = endTime;
    }

    @Override
    public void run() {

        while (System.currentTimeMillis() <= endTime) {

            // do something meaningful

        }   
    }
}

public class TestPool {

    public static void main(String[] args) {

        // create thread pool with given size
        ExecutorService service = Executors.newFixedThreadPool(1000); 

        long startTime = System.currentTimeMillis();
        long endTime = startTime + (30 * 60 * 1000);

        for (int i = 0; i < threads; i++) {
            service.submit(new ThreadTask(endTime));
        }

        // wait for termination        
        service.shutdown();
        service.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS); 
    }
}

现在我的问题是-

上面的代码是否保证每个线程同时启动并运行30 minutes?我不确定将线程放入线程池需要多少时间。但看起来有些线程可能会启动得有点晚,并且它们不会完全运行30 minutes,可能不到 30 分钟。

我正在寻找每个线程应该同时启动并且它们应该 准确运行30 minutes

【问题讨论】:

  • 不,它们不会同时启动,不,它们不会完全运行 30 分钟,具体取决于“有意义的事情”需要多长时间。

标签: java multithreading threadpool executorservice


【解决方案1】:

简短回答:不,所有线程不会同时启动(取决于您的容差,它可能“相当”可以忽略不计)。并且取决于有意义的事情,每个线程运行 30 分钟的可能性很小(同样,您的时间粒度可能会使这个断言出错)。

线索

  • 为确保最大限度地提高所有线程开始时尽可能靠近彼此的机会,请先创建线程,然后将其提交给执行程序。与其他语言一样,在 Java 中创建线程是一项昂贵的操作。
  • 为了让线程精确运行 30 分钟,我建议每个线程自行计算其终止时间,因为您当前传递给构造函数的参数可能已经影响了您的精度(由于线程创建时间)。
  • 通常不建议(除非您在怪物机器或微积分网格上运行 java)创建具有 1000 个线程的线程池。请记住,如果物理机的内核数不如线程数,那么每次 JVM 决定应该运行哪个线程时都会发生上下文切换。

编辑

public class TestPool {

    public static void main(String[] args) {

        // create thread pool with given size
        ExecutorService service = Executors.newFixedThreadPool(10); 

        long startTime = System.currentTimeMillis();
        long endTime = startTime + (30 * 60 * 1000);

        ThreadTask[] threadTasks = new ThreadTask[threads];
        for (int i = 0; i < threads; i++) {
            threadTasks[i] = new ThreadTask(endTime);
        }

        for (ThreadTask tt : threadTasks) {
            service.submit(tt);
        }

        // wait for termination        
        service.shutdown();
        service.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS); 
    }
}

【讨论】:

  • 感谢aymeric 的建议。我最感兴趣的是你的第一点。我怎样才能做到这一点?你能用我的代码提供一个例子吗?这样我就能更好地理解了。感谢您的帮助。
【解决方案2】:

乍一看,这看起来像是一个有点不切实际的多线程练习项目。但是你说我正在开发一个多线程程序,这表明它有一个真实的应用程序背景。

如果是这样:不要仅仅因为可以就创建 1000 个线程。相反,请说出您真正想要实现的目标。

关于您的要求:要以最小延迟几乎同时启动所有线程,您可以prestartAllCoreThreadsThreadPoolExecutor。提交在其 run 方法中包含 // do something meaningful 的 Runnable。要将运行时间限制为 30 分钟,请安排一个 TimerTask,在 30 分钟后使用 shutdownNow 关闭 ThreadPoolExecutor。在创建 ThreadPoolExecutor 时,您可以使用一个固定大小的 BlockingQueue,其大小按照您想要的线程数顺序排列,以避免提交过多的作业。

【讨论】:

    【解决方案3】:

    考虑使用倒计时锁存器来实现最大并行度。基本上,您可以创建总计数为 1 的单例/静态 countdownLatch 并让多个线程等待相同的倒计时。检查下面我做了什么

    指定线程开始时间的主线程。

    package mylab.threads;
    
    import java.util.TimerTask;
    import java.util.concurrent.CountDownLatch;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    
    public class MainThread extends TimerTask {
    
        private static CountDownLatch countDown = new CountDownLatch(1);
    
        private ExecutorService es = Executors.newCachedThreadPool();
    
        @Override
        public void run() {
    
        try {
    
    
            Thread1 thread1 = new Thread1();
            thread1.setDoneSignal(countDown);
            es.submit(thread1);
    
            Thread2 thread2 = new Thread2();
            thread2.setDoneSignal(countDown);
            es.submit(thread2);
    
            System.out.println("waiting main.. ");
            synchronized(this) {
            this.wait(2000);
            }
            System.out.println("kick off threads..");
            countDown.countDown();
    
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    
        }
    
    }
    

    定义要并行运行的线程

    package mylab.threads;
    
    import java.util.Date;
    import java.util.TimerTask;
    import java.util.concurrent.CountDownLatch;
    
    public class Thread1 extends TimerTask{
    
        private CountDownLatch doneSignal = null;
    
        /**
         * @return the doneSignal
         */
        public CountDownLatch getDoneSignal() {
            return doneSignal;
        }
    
        /**
         * @param doneSignal the doneSignal to set
         */
        public void setDoneSignal(CountDownLatch doneSignal) {
            this.doneSignal = doneSignal;
        }
    
        @Override
        public void run() {
    
        try {
            this.doneSignal.await();
            System.out.println("get going thread 1 -"+new Date().getTime());
            synchronized(this) {
            this.wait(3000);
            }
            System.out.println("Exiting thread 1 - "+new Date().getTime());
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        }
    
    }
    
    
    package mylab.threads;
    
    import java.util.Date;
    import java.util.TimerTask;
    import java.util.concurrent.CountDownLatch;
    
    public class Thread2 extends TimerTask{
    
        private CountDownLatch doneSignal = null;
    
        /**
         * @return the doneSignal
         */
        public CountDownLatch getDoneSignal() {
            return doneSignal;
        }
    
        /**
         * @param doneSignal the doneSignal to set
         */
        public void setDoneSignal(CountDownLatch doneSignal) {
            this.doneSignal = doneSignal;
        }
    
        @Override
        public void run() {
    
        try {
            this.doneSignal.await();
            System.out.println("get going thread 2 -"+new Date().getTime());
            synchronized(this) {
            this.wait(3000);
            }
            System.out.println("Exiting thread 2 - "+new Date().getTime());
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        }
    }
    

    最后运行主线程。

    package mylab.threads;
    
    public class ThreadTest {
    
        /**
         * @param args
         */
        public static void main(String[] args) {
    
        MainThread mt = new MainThread();
        mt.run();
    
        }
    
    }
    

    这是输出

    waiting main.. 
    kick off threads..
    get going thread 1 -1387513662107
    get going thread 2 -1387513662107
    Exiting thread 1 - 1387513665108
    Exiting thread 2 - 1387513665108
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-03-21
      • 2017-08-28
      • 1970-01-01
      • 2023-03-31
      • 1970-01-01
      • 2015-01-29
      • 2010-10-14
      相关资源
      最近更新 更多