Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/codeigniter/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 后台线程中运行的可编辑任务队列_Java_Multithreading_Queue_Executorservice - Fatal编程技术网

Java 后台线程中运行的可编辑任务队列

Java 后台线程中运行的可编辑任务队列,java,multithreading,queue,executorservice,Java,Multithreading,Queue,Executorservice,我知道这个问题被回答了很多次,但我很难理解它是如何工作的 因此,在我的应用程序中,用户必须能够选择要添加到队列中的项目(使用observeList在列表视图中显示),并且每个项目都需要由ExecutorService按顺序处理 此外,该队列应该是可编辑的(更改顺序并从列表中删除项目) 显然,这不起作用,因为它期待一个可观察的列表。有一种优雅的方法可以做到这一点?我能想到的最简单的解决方案是在执行器之外维护任务列表,并使用回调向执行器提供下一个可用的任务。不幸的是,它涉及到任务列表上的同步和一个A

我知道这个问题被回答了很多次,但我很难理解它是如何工作的

因此,在我的应用程序中,用户必须能够选择要添加到队列中的项目(使用
observeList
列表视图中显示),并且每个项目都需要由
ExecutorService
按顺序处理

此外,该队列应该是可编辑的(更改顺序并从列表中删除项目)


显然,这不起作用,因为它期待一个可观察的列表。有一种优雅的方法可以做到这一点?

我能想到的最简单的解决方案是在执行器之外维护任务列表,并使用回调向执行器提供下一个可用的任务。不幸的是,它涉及到任务列表上的同步和一个
AtomicBoolean
来指示正在执行的任务

回调只是一个
Runnable
,它将原始任务包装起来运行,然后“回调”以查看是否还有其他任务要执行,如果有,则使用(后台)执行器执行

为了使任务列表保持有序并处于已知状态,需要进行同步。任务列表可以由两个线程同时修改:通过在执行者(后台)线程中运行的回调和通过UI前台线程执行的
handleItemClicked
方法。这反过来意味着,例如,任务列表为空时,永远无法确切知道。为了使任务列表保持有序并处于已知的固定状态,需要同步任务列表

这仍然留下了一个模糊的时刻来决定任务何时准备好执行。这就是
AtomicBoolean
的作用:值集总是立即可用并由任何其他线程读取,而
compareAndSet
方法将始终确保只有一个线程获得“OK”

将同步和原子布尔函数的使用结合起来,可以创建一个具有“关键部分”的方法,前台线程和后台线程可以同时调用该方法,以触发新任务的执行(如果可能)。下面的代码的设计和设置方式使一个这样的方法(
runnextask
)可以存在。使并发代码中的“关键部分”尽可能简单和明确是一种很好的做法(这通常会导致高效的“关键部分”)

import java.util.*;
导入java.util.concurrent.*;
导入java.util.concurrent.AtomicBoolean;
公共类序列化任务队列{
公共静态void main(字符串[]args){
ExecutorService executor=Executors.newSingleThreadExecutor();
//此列表上的所有操作必须在列表本身上同步。
SerialTaskQueue tq=新的SerialTaskQueue(执行器);
试一试{
//逐个测试运行任务
tq.add(新的睡眠型(10L));
睡眠(5L);
tq.add(新的睡眠型(20L));
tq.add(新的睡眠型(30L));
睡眠(100L);
System.out.println(“队列大小:+tq.size());//应为空
tq.add(新的睡眠型(10L));
睡眠(100L);
}捕获(例外e){
e、 printStackTrace();
}最后{
执行者。关机现在();
}
}
//必须在列表上同步对列表的所有查找和修改。
私有最终列表任务=新建LinkedList();
//原子布尔,用于确保在任何给定时间只执行1个任务
private final AtomicBoolean ExecuteExtTask=新AtomicBoolean(true);
私人最终执行人;
public SerialTaskQueue(执行器执行器){
this.executor=执行人;
}
公共void添加(可运行任务){
已同步(任务){tasks.add(任务);}
RunNextask();
}
私有void runNextTask(){
//确保执行一项任务的关键部分。
已同步(任务){
如果(!tasks.isEmpty()
&&ExecuteExtTask.compareAndSet(真、假)){
executor.execute(wrapTask(tasks.remove(0));
}
}
}
专用CallbackTask wrapTask(可运行任务){
返回新的CallbackTask(task,newrunnable(){
@重写公共无效运行(){
如果(!ExecuteExtTask.compareAndSet(false,true)){
System.out.println(“错误:编程错误,回调应始终在执行状态下运行。”);
}
runNextTask();
}
});
}
公共整数大小(){
已同步(任务){return tasks.size();}
}
公共可运行get(int索引){
已同步(任务){返回任务。获取(索引);}
}
公共可运行删除(int索引){
已同步(任务){返回任务。删除(索引);}
}
//常规回调任务,请参阅https://stackoverflow.com/a/826283/3080094
静态类CallbackTask实现Runnable{
私有最终可运行任务,回调;
公共回调任务(可运行任务,可运行回调){
this.task=任务;
this.callback=回调;
}
@重写公共无效运行(){
试一试{
task.run();
}捕获(例外e){
e、 printStackTrace();
}最后{
试一试{
callback.run();
}捕获(例外e){
e、 printStackTrace();
}
}
}
}
//只睡一会儿的任务
静态类SleepSome实现可运行{
静态长启动时间=System.currentTimeMillis();
私人最终长睡眠时间;
公共睡眠时间(长睡眠时间){
this.sleepTimeMs=sleepTimeMs;
}
@重写公共无效运行(){
试一试{
private void handleItemClicked(MouseEvent event) {
    if (event.getClickCount() == 2) {
        File item = listView.getSelectionModel().getSelectedItem();
        Task<Void> task = createTask(item);
        facade.getTaskQueueList().add(task); // this list is bound to a ListView, where it can be edited
        Future result = executor.submit(task); 
        // where executor is an ExecutorService of which type?

        try {
            result.get();
        } catch (Exception e) {
            // ...
        }
    }
}
ListProperty<Runnable> listProperty = new SimpleListProperty<>();
listProperty.set(taskQueue.getTaskList()); // getTaskList() returns the LinkedList from SerialTaskQueue
queueListView.itemsProperty().bind(listProperty); 
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicBoolean;

public class SerialTaskQueue {

    public static void main(String[] args) {

        ExecutorService executor = Executors.newSingleThreadExecutor();
        // all operations on this list must be synchronized on the list itself.
        SerialTaskQueue tq = new SerialTaskQueue(executor);
        try {
            // test running the tasks one by one
            tq.add(new SleepSome(10L));
            Thread.sleep(5L);
            tq.add(new SleepSome(20L));
            tq.add(new SleepSome(30L));

            Thread.sleep(100L);
            System.out.println("Queue size: " + tq.size()); // should be empty
            tq.add(new SleepSome(10L));

            Thread.sleep(100L);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            executor.shutdownNow();
        }
    }

    // all lookups and modifications to the list must be synchronized on the list.
    private final List<Runnable> tasks = new LinkedList<Runnable>();
    // atomic boolean used to ensure only 1 task is executed at any given time
    private final AtomicBoolean executeNextTask = new AtomicBoolean(true);
    private final Executor executor;

    public SerialTaskQueue(Executor executor) {
        this.executor = executor;
    }

    public void add(Runnable task) {

        synchronized(tasks) { tasks.add(task); }
        runNextTask();
    }

    private void runNextTask() {
        // critical section that ensures one task is executed.
        synchronized(tasks) {
            if (!tasks.isEmpty()
                    && executeNextTask.compareAndSet(true, false)) {
                executor.execute(wrapTask(tasks.remove(0)));
            }
        }
    }

    private CallbackTask wrapTask(Runnable task) {

        return new CallbackTask(task, new Runnable() {
            @Override public void run() {
                if (!executeNextTask.compareAndSet(false, true)) {
                    System.out.println("ERROR: programming error, the callback should always run in execute state.");
                }
                runNextTask();
            }
        });
    }

    public int size() {
        synchronized(tasks) { return tasks.size(); }
    }

    public Runnable get(int index) {
        synchronized(tasks) { return tasks.get(index); }
    }

    public Runnable remove(int index) {
        synchronized(tasks) { return tasks.remove(index); }
    }

    // general callback-task, see https://stackoverflow.com/a/826283/3080094
    static class CallbackTask implements Runnable {

        private final Runnable task, callback;

        public CallbackTask(Runnable task, Runnable callback) {
            this.task = task;
            this.callback = callback;
        }

        @Override public void run() {
            try {
                task.run();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                try {
                    callback.run();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    // task that just sleeps for a while
    static class SleepSome implements Runnable {

        static long startTime = System.currentTimeMillis();

        private final long sleepTimeMs;
        public SleepSome(long sleepTimeMs) {
            this.sleepTimeMs = sleepTimeMs;
        }
        @Override public void run() {
            try { 
                System.out.println(tdelta() + "Sleeping for " + sleepTimeMs + " ms.");
                Thread.sleep(sleepTimeMs);
                System.out.println(tdelta() + "Slept for " + sleepTimeMs + " ms.");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        private String tdelta() { return String.format("% 4d ", (System.currentTimeMillis() - startTime)); }
    }
}