Java 具有ServletContextListener的线程池

Java 具有ServletContextListener的线程池,java,multithreading,Java,Multithreading,我想运行一些简单的后台进程计算,但我似乎无法理解。不管我做什么,它都会阻塞 public class WorkThreadManagerContextLoaderListener implements ServletContextListener { private Runnable runnable; private WorkManager workManager; @Override public void contextInitialized(Servle

我想运行一些简单的后台进程计算,但我似乎无法理解。不管我做什么,它都会阻塞

public class WorkThreadManagerContextLoaderListener implements ServletContextListener {
    private Runnable runnable;
    private WorkManager workManager;

    @Override
    public void contextInitialized(ServletContextEvent event) {
        final WebApplicationContext springContext = WebApplicationContextUtils.getWebApplicationContext(event.getServletContext());
        workManager = (WorkManager) springContext.getBean("workThreadManager");

        runnable = new WorkThreadManagerStartUp(WorkManager);

        runnable.run();
    }

    @Override
    public void contextDestroyed(ServletContextEvent event) {
        workManager.shutDown();
    }
}
WorkThreadManagerStartUp之所以存在,是因为我不想阻止它,所以我将其设置为可运行类型,并且在调用run()时,它会启动ExecutorService:

public class UnitOfWorkThreadManagerStartUp implements Runnable {
    private WorkManager workManager;

    public UnitOfWorkThreadManagerStartUp(WorkManager workManager) {
        this.workManager = workManager;
    }

    @Override
    public void run() {
        workManager.startUp();
    }
}

public class WorkThreadManager implements WorkManager {
    @Autowired
    private WorkService workService;

    private final int availableProcessors = Runtime.getRuntime().availableProcessors();
    private final ExecutorService executorService = Executors.newFixedThreadPool(4 * availableProcessors);

    @Override
    public void startUp() {
        // this method always blocks...
    }
}
但我的解决方案并没有如预期的那样有效。我正在运行Tomcat 7.0.30

我想弄明白的是,我如何在后台启动线程池,而不停止部署web应用,因为由于startUp()始终处于阻塞状态,目前它无法完全联机。我想简化这个解决方案,如果不需要WorkThreadManagerStartUp类,还可以删除它

编辑:

我修改了启动课程

public class WorkThreadManagerStartUp implements Runnable {
    private WorkManager workManager;

    public WorkThreadManagerStartUp(WorkManager workManager) {
        this.workManager = workManager;
    }

    @Override
    public void run() {
    try {
        while (true) {
                System.out.println("Hello World!");
                Thread.sleep(1000 * 10);
            }
        } catch(InterruptedException e) {
            System.out.println(e.getMessage());
        }
    }
}

虽然这是假设运行在它自己的线程,你好世界!按预期显示多次,但不允许web应用联机。

查看您的源代码,我没有看到任何实际创建的线程。通常,您可以执行以下操作来分叉线程:

new Thread(new WorkThread(...)).start();
这将在新线程中调用
WorkThread.run()
方法。如果您使用的是
执行器服务
(通常推荐使用
线程的“手动”代码),则您可以执行以下操作:

executorService.submit(new WorkThread(...));
...
// when done with the service you have to shut it down
executorService.shutdown();
如果将
WorkManager
类注入到侦听器类中,那么我只需在管理器上添加一个
submit(…)
方法,并在侦听器中执行如下操作:

workManager.submit(new WorkThread());
这意味着不需要使用
WorkThreadManagerStartUp
类。您向服务提交工作线程或工作单元


就Spring而言,我只需要让您的
WorkManager
类实现
InitializingBean
DisposableBean
,这样它就可以自己启动和停止服务了。没有理由让另一个豆子这么做。然后,您可以使用管理器管理的
ExecutorService
将管理器注入任何想要运行
工作线程的类。

查看您的源代码,我没有看到任何实际创建的线程。通常,您可以执行以下操作来分叉线程:

new Thread(new WorkThread(...)).start();
这将在新线程中调用
WorkThread.run()
方法。如果您使用的是
执行器服务
(通常推荐使用
线程的“手动”代码),则您可以执行以下操作:

executorService.submit(new WorkThread(...));
...
// when done with the service you have to shut it down
executorService.shutdown();
如果将
WorkManager
类注入到侦听器类中,那么我只需在管理器上添加一个
submit(…)
方法,并在侦听器中执行如下操作:

workManager.submit(new WorkThread());
这意味着不需要使用
WorkThreadManagerStartUp
类。您向服务提交工作线程或工作单元


就Spring而言,我只需要让您的
WorkManager
类实现
InitializingBean
DisposableBean
,这样它就可以自己启动和停止服务了。没有理由让另一个豆子这么做。然后,您可以使用管理器管理的
ExecutorService
将管理器注入任何想要运行
WorkThread
的类。

通常,您将需要完成的工作放在Runnable的run方法中,让线程隐式调用该方法,但您自己正在调用它。不太清楚你想做什么。您所说的方法中有什么是阻塞的?我正在从ServletContextListener实例化WorkThreadManagerStartUp。当我调用run方法时,我希望它在后台继续工作,而不会中断web应用程序的启动,您应该执行
新线程(runnable).start()。这样它将在一个新的独立线程中运行。没有错误。是的。我应该叫start而不是run。我现在明白你所说的“自己调用它”是什么意思了。通常你把需要做的事情放在Runnable的run方法中,让线程隐式地调用该方法,但你自己调用它。不太清楚你想做什么。您所说的方法中有什么是阻塞的?我正在从ServletContextListener实例化WorkThreadManagerStartUp。当我调用run方法时,我希望它在后台继续工作,而不会中断web应用程序的启动,您应该执行
新线程(runnable).start()。这样它将在一个新的独立线程中运行。没有错误。是的。我应该叫start而不是run。我现在明白你所说的“自己调用它”是什么意思了。我同意你应该将executor服务作为一种通用的良好实践。您可能还需要一种方法来监视您提交的可运行/可调用任务,并可能让它使用future返回结果。顺便说一句,我没有使用web服务器的经验,但是在web服务器中管理自己的线程不是很糟糕吗?难道没有办法让服务器为您这样做吗?我同意您应该将executor服务作为一种通用的良好实践。您可能还需要一种方法来监视您提交的可运行/可调用任务,并可能让它使用future返回结果。顺便说一句,我没有使用web服务器的经验,但是在web服务器中管理自己的线程不是很糟糕吗?难道没有办法让服务器为您做这件事吗?