java线程等待并自动唤醒

时间:2013-09-25 10:01:04

标签: java multithreading

我有一个Web应用程序,它接受来自用户的一些数据来创建任务,然后应该执行任务。

由于任务的执行是从互联网下载的东西,这将花费一些时间,所以我试图创建一个新的线程来完成这项工作。

这是我的想法:

  1. 创建用于下载数据的LoaderThread。并且LoaderThread包含ArrayList字段用于放置Task

  2. 处理请求和响应的Servlet

  3. Servlet启动时,启动LoaderThread

  4. 在servlet运行期间,将任务添加到LoaderThread

  5. 这是代码(其中一些被省略):

    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实例?如果是这样,如何避免呢?


    似乎我可以使用其他实现,但我想知道我的案例是否可以重构?

    因为我想学习一些我错过的东西。 :) 谢谢。

2 个答案:

答案 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

    }
}

请参阅link with example

答案 1 :(得分:0)

您的用例需要ExecutorService,您已经开始从头开始重新实现它。现在最好停下来,使用标准库中完成的,无错误,灵活且功能强大的产品。