javafx后台任务:在另一个服务中调用服务

时间:2013-09-22 12:48:15

标签: multithreading javafx task

我想执行执行多个后台任务的后台任务。我实际上要做的是执行一个后台进程,为列表中的每个Object执行一些代码,并在固定的线程池中执行。因此,例如,我在列表中有100个用户,我同时执行每个用户的代码,但同时不超过5个。

因此我使用两个服务/任务对:一个服务/任务用于在整个用户列表上执行,该服务使用固定线程池作为其执行者,并为每个用户执行一系列第二服务/任务对清单。

如下例所示:

class MainService extends Service<List<User>> {

    private List<User> users;

    public MainService(List<User> users) { this.users=users; }

    protected Task<List<User>> createTask(){
      return new MainTask(this.users)
    }
}

class Maintask extends Task<List<User>> {

     private List<User> users;
     private Executor executor;

     public MainTask(List<User> users) { 
       this.users=users; 
       this.executor=Executors.newFixedThreadPool(5);
     }

     protected List<User> call() throws Exception {
        for (User user : this.users) { 
            System.out.println("Starting single service");
            SingleService service=new SingleService(user)
            service.setExecutor(this.executor);
            service.start();
            System.out.println("Single service started");
        }
     }
}

class SingleService extends Service<User> {

      private User user;

      public SingleService(User user) { this.user=user; }

      protected Task<User> createTask() {
        return new SingleTask(this.user)
      }
}

class SingleTask extends Task<User> {

     private User user;

    public SingleTask(User user) { this.user=user; }

    protected User call() throws Exception() {
       // Do some work
    }
}

代码执行到第一次打印“启动单一服务”的时刻,根本没有打印“单一服务已启动”消息。据我所知,SingleService已启动,但其createTask()根本没有被执行。我在这里犯了一些错误吗?

1 个答案:

答案 0 :(得分:0)

好吧,我正在尝试在不同的环境中做同样的事情......从单个主服务启动多个服务。 我已经覆盖了所有服务方法,这是我的打印输出:

  • 只能在FX Application Thread {from onFailed()method}
  • 中使用服务

服务不在FX线程上运行,但只能从FX线程调用。 因此,服务或任务中调用的所有服务和任务都不会被执行。

这是我的工作:

public class FXComponentImporter extends Service<Void> implements JarImporter {
    //Scanner<T> = Service<List<Class<T>>>
    private Scanner<Node> nodeScanner = null;
    private Scanner<Paint> paintScanner = null;
    private Scanner<Animation> animationScanner = null;

    private static int nodeCount = 0, paintCount = 0, animationCount = 0;
    private final ObservableMap<String, Class<?>> foundComponents = FXCollections.observableHashMap();

    public FXComponentImporter() {
        this(null);
    }

    public FXComponentImporter(File file) {
        if (file != null) {
            try {
                this.nodeScanner = new Scanner<>(file, Node.class);
                this.paintScanner = new Scanner<>(file, Paint.class);
                this.animationScanner = new Scanner<>(file, Animation.class);
            } catch (IOException ex) {
                Logger.getLogger(FXComponentImporter.class.getName()).log(Level.SEVERE, null, ex);
            }
        } else {
            File f = importJar();
            try {
                this.nodeScanner = new Scanner<>(f, Node.class);
                this.paintScanner = new Scanner<>(f, Paint.class);
                this.animationScanner = new Scanner<>(f, Animation.class);
            } catch (IOException ex) {
                Logger.getLogger(FXComponentImporter.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
        this.scanningDone.bind(this.nodeScanningDone.and(this.paintScanningDone.and(this.animationScanningDone)));

        this.scanningDone.addListener(new ChangeListener<Boolean>() {
            @Override
            public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
                if (newValue) {
                    if(scanningDone.isBound()){
                        scanningDone.unbind();
                    }                    
                    start();
                    scanningDone.removeListener(this);
                }
            }
        });

        startScanning();
    }

    @Override
    protected Task<Void> createTask() {
        return new Task<Void>() {
            @Override
            protected Void call() throws Exception {
                Map<String, Class<?>> map = new HashMap<>();
                List<Class<Node>> nodes = new ArrayList<>();
                List<Class<Paint>> paints = new ArrayList<>();
                List<Class<Animation>> anims = new ArrayList<>();

                CountDownLatch latch = new CountDownLatch(1);
                //Platform needed due to Service only accessed from FX thread 
                Platform.runLater(() -> {
                    try {
                        //FX Stuff done here
                        nodes.addAll(nodeScanner.getMatchingClasses());
                        paints.addAll(paintScanner.getMatchingClasses());
                        anims.addAll(animationScanner.getMatchingClasses());

                    } finally {
                        latch.countDown();
                    }
                });
                latch.await();

                this.updateMessage("Scanning for Nodes ... ");
                nodes.stream().forEach(n -> {
                    if(n != null){
                        map.putIfAbsent(n.getSimpleName(), n);
                    }
                    nodeCount++;
                });
                this.updateMessage("Found : " + nodeCount + " Nodes ... ");

                this.updateMessage("Scanning for Paints ... ");
                paints.stream().forEach(p -> {
                    if(p != null){
                        map.putIfAbsent(p.getSimpleName(), p);
                    }
                    paintCount++;
                });
                this.updateMessage("Found : " + paintCount + " Paints ... ");

                this.updateMessage("Scanning for Animations ... ");
                anims.stream().forEach(a -> {
                    if(a != null){
                        map.putIfAbsent(a.getSimpleName(), a);
                    }
                    animationCount++;
                });
                this.updateMessage("Found : " + animationCount + " Animations ... ");

                foundComponents.putAll(map);

                return null;
            }
        };
    }

    @Override
    protected void executeTask(Task<Void> task) {
        super.executeTask(task);
        System.out.println(getClass().getSimpleName() + " is Executing " + task.getTitle());
    }

    @Override
    protected void cancelled() {
        super.cancelled(); 
        System.out.println(getClass().getSimpleName() + " was Cancelled ... ");
    }

    @Override
    protected void running() {
        super.running();
        System.out.println(getClass().getSimpleName() + " is Running ... ");
    }

    @Override
    protected void ready() {
        super.ready();
        System.out.println(getClass().getSimpleName() + " is Ready! ... ");
    }

    @Override
    protected void scheduled() {
        super.scheduled();
        System.out.println(getClass().getSimpleName() + " is Scheduled ... ");
    }

    @Override
    protected void failed() {
        super.failed();
        System.out.println(getException().getMessage());
    }

    @Override
    protected void succeeded() {
        super.succeeded();
        System.out.println("Importing Succeeded ... with: " + foundComponents.entrySet().size() + " results.\n");

        foundComponents.forEach((s, c) -> {
            System.out.println(c.getSuperclass().getSimpleName() + " >> " + s + " : " + c.getSimpleName());
        });
    }

    @Override
    public void restart() {
        super.restart(); 
        System.out.println(getClass().getSimpleName() + " is Restarting ... ");
    }




    private void startScanning() {
        nodeScanner.stateProperty().addListener(nsl);
        paintScanner.stateProperty().addListener(psl);
        animationScanner.stateProperty().addListener(asl);

        nodeScanner.start();
        paintScanner.start();
        animationScanner.start();
    }

    private final BooleanProperty scanningDone = new SimpleBooleanProperty(false);
    private final BooleanProperty nodeScanningDone = new SimpleBooleanProperty(false);
    private final BooleanProperty paintScanningDone = new SimpleBooleanProperty(false);
    private final BooleanProperty animationScanningDone = new SimpleBooleanProperty(false);

    private final ChangeListener nsl = new ChangeListener<Worker.State>() {
        @Override
        public void changed(ObservableValue<? extends State> observable, State oldValue, State newValue) {
            if (newValue.equals(State.SUCCEEDED)) {
                nodeScanningDone.set(true);
                nodeScanner.stateProperty().removeListener(this);
            }
        }
    };
    private final ChangeListener psl = new ChangeListener<Worker.State>() {
        @Override
        public void changed(ObservableValue<? extends State> observable, State oldValue, State newValue) {
            if (newValue.equals(State.SUCCEEDED)) {
                paintScanningDone.set(true);
                paintScanner.stateProperty().removeListener(this);
            }
        }
    };
    private final ChangeListener asl = new ChangeListener<Worker.State>() {
        @Override
        public void changed(ObservableValue<? extends State> observable, State oldValue, State newValue) {
            if (newValue.equals(State.SUCCEEDED)) {
                animationScanningDone.set(true);
                animationScanner.stateProperty().removeListener(this);
            }
        }
    };


    public ObservableMap<String, Class<?>> getFoundComponents() {
        return foundComponents;
    }    
}

和我的界面,如果你想尝试一下:

public interface JarImporter {
    public static File defaultDirectory = new File(System.getProperty("user.home"));
    public static final FileChooser.ExtensionFilter classfilter = new FileChooser.ExtensionFilter("Jar files", "*.jar");

    static FileChooser defaultFileChooser(){
        FileChooser fc = new FileChooser();
        fc.getExtensionFilters().add(classfilter);
        fc.setInitialDirectory(defaultDirectory);
        return fc;
    }

    public default File importJar(){
        File jar = defaultFileChooser().showOpenDialog(null);
        if(jar != null){
            return jar;
        }else{
            return null;
        }
    } 
}

希望这会有所帮助..虽然只是看了问题日期,但是不久前......