Is there an out-of-the-box thread pool with multiple queues (that ensure serial processing of each queue)?

后端 未结 7 688
星月不相逢
星月不相逢 2020-12-16 11:22

Among all my tasks, I have some that must be processed serially (they can never run concurrently and they must be processed in order).

I achieved that creating a sep

7条回答
  •  挽巷
    挽巷 (楼主)
    2020-12-16 12:08

    Look into Java's built-in thread executor service.

    http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ExecutorService.html

    There is a single thread executor that will process each task synchronously.

    In response to the comments section:

    Please read the API before you say this won't work.
    http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Executors.html#newSingleThreadExecutor()

    public static ExecutorService newSingleThreadExecutor() Creates an Executor that uses a single worker thread operating off an unbounded queue. (Note however that if this single thread terminates due to a failure during execution prior to shutdown, a new one will take its place if needed to execute subsequent tasks.) Tasks are guaranteed to execute sequentially, and no more than one task will be active at any given time. Unlike the otherwise equivalent newFixedThreadPool(1) the returned executor is guaranteed not to be reconfigurable to use additional threads.

    Note: is states they are guaranteed to execute sequentially.

    EDIT:

    Now that I understand your question better, I have an idea you could try. If you maintain a queue for each group, you can pull items off each queue and feed them into a thread pool. The code below won't prioritize any one group, it just pulls them in a round robbing fashion. If you need to add prioritization you should easily be able to. The following code will round robbing 4 groups using two threads (plus the thread managing the queue). You can use another queue mechanism. I typically use LinkedBlockingQueue for situations where I want to wait for items to be placed on the queue by another thread, which probably is not what you want - which is why I'm polling instead of calling take(). Take is the call that waits.

    private Future group1Future = null;
    private Future group2Future = null;
    private Future group3Future = null;
    private Future group4Future = null;
    private LinkedBlockingQueue group1Queue
            = new LinkedBlockingQueue<>();
    private LinkedBlockingQueue group2Queue
            = new LinkedBlockingQueue<>();
    private LinkedBlockingQueue group3Queue
            = new LinkedBlockingQueue<>();
    private LinkedBlockingQueue group4Queue
            = new LinkedBlockingQueue<>();
    
    private ExecutorService executor = Executors.newFixedThreadPool(2);
    
    
    public void startProcessing() {
        while (true) {
            if (group1Future != null && group1Future.isDone()) {
                if (group1Queue.peek() != null) {
                    group1Future = executor.submit(group1Queue.poll());
                }
            }
            if (group2Future != null && group1Future.isDone()) {
                if (group2Queue.peek() != null) {
                    group2Future = executor.submit(group2Queue.poll());
                }
            }
            if (group3Future != null && group3Future.isDone()) {
                if (group3Queue.peek() != null) {
                    group3Future = executor.submit(group3Queue.poll());
                }
            }
    
            if (group4Future != null && group4Future.isDone()) {
                if (group4Queue.peek() != null) {
                    group4Future = executor.submit(group4Queue.poll());
                }
            }
        }
    }
    

    If a task for that group is not complete, it will skip to the next group. No more than two groups will be processed at a time and no single group will ever run more than one task. The queues will enforce ordered execution.

提交回复
热议问题