简体   繁体   中英

java thread wait and auto wake up

I have an web application which accept some data from user to create a task, then the task should be executed.

Since the execution of the Task is to download something from the internet which will cost some time, so I tried to create a new Thread to do the job.

This is my idea:

  1. create a LoaderThread used to download data. And the LoaderThread hold a field of ArrayList used for put the Task .

  2. A Servlet to handle the request and response.

  3. When the Servlet startup, start the LoaderThread

  4. During the servlet run, add task to the LoaderThread .

This is the code(some of them is omitted):

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();
    }
}

The above code worked, but I found that even the tasks were empty and there are no new task added, the loop will keep running.

So I though if I can make the LoaderThread suspend when there are no tasks, and notify it when new task come out.

So I tried this:

@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();
            }

        }
    }
}

I tried to call the wait() if the tasks is empty.

But I do not know how to wake up it?

Also, is there anything I should know to improve the application?

BWT, is it possible that more than one LoaderThread instance will be created? If so , how to avoid it?


It seems that I can use other implementation, but I wonder if my case is refactor-able?

Since I want to learn some thing I have missed. :) Thanks.

Your requirements are the standard usage of ExecutorService , so I would recommend you to use ExecutorService and not reinvent the wheel.

Base on code you provided, your servlet should look like this:

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

    }
}

See link with example

Your use case calls for an ExecutorService and you have started reimplementing it from scratch. Better stop now and use the finished, bug-free, flexible, and powerful product from the standard library.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM