Executors Factory方法newScheduledThreadPool始终返回相同的线程池

时间:2013-11-06 14:32:25

标签: java multithreading executorservice scheduledexecutorservice

根据Java规范: public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) “创建一个线程池,可以安排命令在给定的延迟后运行,或者定期执行。”

但是根据我的经验,即使我创建两个单独的ScheduledExecutorService两次调用newScheduledThreadPool(int corePoolSize)工厂方法并安排两个完全不同的Callable任务,两个线程同步运行,即一个等待另一个。考虑到已经创建了两个单独的线程池,它们应该同时运行。

public static ScheduledExecutorService SCANNER_SERVICE = Executors.newScheduledThreadPool(10);
public static ScheduledExecutorService UNSERVICERESTORED_SCANNER_SERVICE = Executors.newScheduledThreadPool(10);

Scanner scanner=new Scanner();
UnServiceRestoredTicketScanner unServiceRestoredTicketScanner=new UnServiceRestoredTicketScanner();

if(SCANNER_SERVICE.isShutdown())
    SCANNER_SERVICE=Executors.newScheduledThreadPool(10);
SCANNER_SERVICE.scheduleWithFixedDelay(scanner, 0, 30, TimeUnit.SECONDS);


if(UNSERVICERESTORED_SCANNER_SERVICE.isShutdown())
    UNSERVICERESTORED_SCANNER_SERVICE=Executors.newScheduledThreadPool(10);
UNSERVICERESTORED_SCANNER_SERVICE.scheduleWithFixedDelay(unServiceRestoredTicketScanner, 0, 40, TimeUnit.SECONDS);

输出:

Scanner Thread started - com.csp.productionsupport.queuemonitor.events.Scanner@1fa6d18
ServiceRestoredTicketScanner Thread started - com.csp.productionsupport.queuemonitor.events.UnServiceRestoredTicketScanner@15ed659
Thread ended - com.csp.productionsupport.queuemonitor.events.Scanner@1fa6d18
Scanner Thread started - com.csp.productionsupport.queuemonitor.events.Scanner@1fa6d18
ServiceRestoredTicketScanner Thread ended - com.csp.productionsupport.queuemonitor.events.UnServiceRestoredTicketScanner@15ed659
Thread ended - com.csp.productionsupport.queuemonitor.events.Scanner@1fa6d18
Scanner Thread started - com.csp.productionsupport.queuemonitor.events.Scanner@1fa6d18
ServiceRestoredTicketScanner Thread started - com.csp.productionsupport.queuemonitor.events.UnServiceRestoredTicketScanner@15ed659
Thread ended - com.csp.productionsupport.queuemonitor.events.Scanner@1fa6d18
Scanner Thread started - com.csp.productionsupport.queuemonitor.events.Scanner@1fa6d18
ServiceRestoredTicketScanner Thread ended - com.csp.productionsupport.queuemonitor.events.UnServiceRestoredTicketScanner@15ed659
Thread ended - com.csp.productionsupport.queuemonitor.events.Scanner@1fa6d18

2 个答案:

答案 0 :(得分:4)

您的代码存在很多问题,并且您对事情的运作方式有所了解。

首先 - 如评论中已提到的那样 - 您在两个池中使用相同的扫描程序实例。这解释了为什么你只能从“一个”线程获得输出。

由于您为每个30/40秒计划这些线程,因此它们不会在前3-4次运行中并行运行:

30s: Thread A
40s: Thread B
60s: Thread A
80s: Thread B
90s: Thread A
120s: Thread A + B (it will be "random" which one runs first)

对Thread的概念存在误解。如果您有2个池,每个池有10个线程,或者1个池有20个线程,则无关紧要。在你的例子中,如果你只有1个拥有1个线程的池,它甚至都没有区别。使用多个池的唯一原因是以不同方式管理这些池,而不是让内部线程“单独”运行。因此,要回答您的实际问题,Java内部如何管理这些池并不重要。

我不知道你的其余代码,但是你检查一个池是否关闭然后创建一个新的事实告诉我你的代码中存在一个架构问题。只有在完成所有工作并且主线程需要等待所有线程完成以处理数据或退出时,才需要关闭池。使用线程池来节省线程创建的开销成本,然后一遍又一遍地创建池,这一点毫无意义。

关于您要归档的内容的信息太少,无法提供任何进一步的建议,但我很确定无论您想要做什么,都可以比您提供的方式更简单。如果您重新发布架构帮助可能会有所帮助。

答案 1 :(得分:0)

这是一个场景:

public class ThreadA implements Runnable{

@Override
public void run() {
    // TODO Auto-generated method stub
    Date startTime =new Date();
    System.out.println("Thread A started at - "+startTime);
    try {
        Thread.sleep(4000);
    } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    Date endTime =new Date();
    System.out.println("Thread A ended at - "+endTime);
    System.out.println("Time taken by Thread A - "+(endTime.getTime()-startTime.getTime())+"ms");

}}

public class ThreadB implements Runnable {

@Override
public void run() {
    // TODO Auto-generated method stub
    Date startTime = new Date();
    System.out.println("Thread B started at - " + startTime);
    try {
        Thread.sleep(60000);
    } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    Date endTime = new Date();
    System.out.println("Thread B ended at - " + endTime);
    System.out.println("Time taken by Thread B - "+ (endTime.getTime() - startTime.getTime()) + "ms");
}}

public class ExecutorTest {

public static ScheduledExecutorService EXECUTOR_A = Executors.newScheduledThreadPool(10);
public static ScheduledExecutorService EXECUTOR_B = Executors.newScheduledThreadPool(10);

public static void main(String[] args) {
    ThreadA threadA=new ThreadA();
    ThreadB threadB=new ThreadB();

    if(EXECUTOR_A.isShutdown())
        EXECUTOR_A=Executors.newScheduledThreadPool(10);
    EXECUTOR_A.scheduleWithFixedDelay(threadA, 0, 30, TimeUnit.SECONDS);

    if(EXECUTOR_B.isShutdown())
        EXECUTOR_B=Executors.newScheduledThreadPool(10);
    EXECUTOR_B.scheduleWithFixedDelay(threadB, 0, 40, TimeUnit.SECONDS);
}}

<强>输出:

主题A开始于 - 星期四07年12月12日12:22:12 IST 2013年 主题B开始于 - 星期四07年12月12日12:22:12 IST 2013年 线程A结束于 - 星期四07年12月12日12:22:16 IST 2013年 线程A所需时间 - 4025ms
线程A开始于 - 星期四07年12月12日12:22:46 IST 2013年 线程A结束于 - 2007年11月12日12:22:50 IST 2013年 线程A所需时间 - 4010ms
主题B结束于 - 2007年11月12日12:23:12 IST 2013年 线程B所花费的时间 - 59996ms
线程A开始于 - 2007年11月12日12:23:20 IST 2013年 主题A结束于 - 2007年11月12日12:23:24 IST 2013年 线程A所需时间 - 4010ms

按设计完美输出。这是我的场景,但在这里工作得很好。将再次重新检查我的代码。