我有一个Web应用程序,它接受来自用户的一些数据来创建任务,然后应该执行任务。
由于任务的执行是从互联网下载的东西,这将花费一些时间,所以我试图创建一个新的线程来完成这项工作。
这是我的想法:
创建用于下载数据的LoaderThread
。并且LoaderThread
包含ArrayList
字段用于放置Task
。
处理请求和响应的Servlet
。
Servlet
启动时,启动LoaderThread
在servlet运行期间,将任务添加到LoaderThread
。
这是代码(其中一些被省略):
public class RwdServlet extends HttpServlet {
private StaticMapLoader loader;
@Override
public void init() throws ServletException {
super.init();
loader = new StaticMapLoader();
loader.startRunning();
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
Task t=createTask(req);
loader.addTask(t);
}
@Override
public void destroy() {
loader.stopRunning();
}
}
public class StaticMapLoader extends Thread {
private List<Task> tasks = new ArrayList<Task>();
private boolean running = false;
@Override
public void run() {
while (running) {
if (tasks.size() > 0) {
Task t = tasks.get(0);
log.info(t);
if (t != null && t.status == Status.waiting) {
tasks.remove(0);
t.status = Status.running;
downLoad(t);
}
}
}
}
private void downLoad(Task t) {
//download file
}
public void addTask(Task t) {
tasks.add(t);
}
public void startRunning() {
running = true;
this.start();
}
public void stopRunning() {
running = false;
this.interrupt();
}
}
上面的代码有效,但我发现即使tasks
为空,也没有添加新的task
,循环也会继续运行。
所以我可以在没有任务时让LoaderThread
暂停,并在新任务出来时通知它。
所以我尝试了这个:
@Override
public void run() {
while (running) {
if (tasks.size() > 0) {
Task t = tasks.get(0);
log.info(t);
if (t != null && t.status == Status.waiting) {
tasks.remove(0);
t.status = Status.running;
downLoad(t);
}
} else {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
如果wait()
为空,我尝试拨打tasks
。
但我不知道如何唤醒它?
另外,有什么我应该知道的改进应用程序吗?
BWT,是否可能会创建多个LoaderThread
实例?如果是这样,如何避免呢?
似乎我可以使用其他实现,但我想知道我的案例是否可以重构?
因为我想学习一些我错过的东西。 :) 谢谢。
答案 0 :(得分:2)
您的要求是ExecutorService的标准用法,因此我建议您使用ExecutorService而不是重新发明轮子。
根据您提供的代码,您的servlet应如下所示:
public class RwdServlet extends HttpServlet {
private ExecutorService loader;
@Override
public void init() throws ServletException {
super.init();
loader = Executors.newCachedThreadPool();//or use some other executor, google about difference between them
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
Task t=createTask(req); //assume that task implements Runnable or Callable
loader.submit(t); // submit a task to executor after this line your task will start execution in another thread
}
@Override
public void destroy() {
loader.shutdown();//this will destroy executor service but before that it will wait until all already submitted tasks will be executed
}
}
答案 1 :(得分:0)
您的用例需要ExecutorService,您已经开始从头开始重新实现它。现在最好停下来,使用标准库中完成的,无错误,灵活且功能强大的产品。