src/main/java/org/openjfx/core/ImageUtil.java
public static Task updateImageListParallel(
            List<File> imageFiles,
            ArrayList<ImageWrapper> cachedImageWrapperList,
            Consumer<LoadResult> consumerInProgress,
            Consumer<List<ImageWrapper>> consumerDone
    ) {

        // run parallel task which will update main UI thread in JavaFX way
        Task javafxTask = new Task<Void>() {
            @Override
            public Void call() {

                try {

                    ArrayList<ImageUtil.LoadResult> counter = new ArrayList<>();

                    double imageLength = imageFiles.size();

                    getForkJoinPool().submit(
                            () -> {
                                List<ImageWrapper> imageWrapperList = IntStream.range(0, imageFiles.size())
                                        .mapToObj(
                                                i -> {
                                                    File currentFile = imageFiles.get(i);

                                                    ImageWrapper imageWrapper = new ImageWrapper(
                                                            i,
                                                            currentFile,

                                                            null
                                                    );

                                                    return new LoadResult(imageWrapper);
                                                }
                                        )

                                        // All generated images would be filtered out to reduce CPU computing
                                        .filter(
                                                loadResult ->
                                                        !cachedImageWrapperList
                                                                .stream()
                                                                .anyMatch(
                                                                        (theImageWrapper)
                                                                                -> theImageWrapper.file == loadResult.imageWrapper.file
                                                                )
                                        )
                                        .parallel()
                                        .peek(
                                                loadResult -> {

                                                    loadResult.imageWrapper.image = getImageThumbnailFromFile(
                                                            loadResult.imageWrapper.file
                                                    );

                                                }
                                        )
                                        // the place to report progress with the generated images
                                        .peek(result -> {
                                            counter.add(result);
                                            result.progress = (double) counter.size() / imageLength;

                                            consumerInProgress.accept(result);

                                        })
                                        .filter(loadResult -> loadResult.imageWrapper.image != null)
                                        .sorted(
                                                Comparator.comparingInt((a) -> a.imageWrapper.index)
                                        )

                                        .map(loadResult -> loadResult.imageWrapper)

                                        .collect(Collectors.toList());

                                // Done call back
                                consumerDone.accept(imageWrapperList);
                            }
                    );
                } catch (Exception e) {
                    e.printStackTrace();
                }

                return null;
            }
        };

        // make the thread and make it in background to not stop main UI thread
        Thread convertingThread = new Thread(javafxTask);

        convertingThread.setDaemon(true);
        convertingThread.start();

        return javafxTask;

    }
/**
     * Create images in parallel with progress support in UI
     *
     * - Any generated images would be shown in UI immediately
     *
     * @param imageFiles - All selected image files from file dialog
     * @param cachedImageWrapperList - We need to update existed generated wrapper list
     *                               to reduce computing and page blink
     * @param consumerInProgress - Callback on progress with given generated images from file
     * @param consumerDone - Call back when done
     * @return
     */
Create images in parallel with progress support in UI
- Any generated images would be shown in UI immediately


Create images in parallel with progress support in UI - Any generated images would be shown in UI immediately
public static Task updateImageListParallel(
            List<File> imageFiles,
            ArrayList<ImageWrapper> cachedImageWrapperList,
            Consumer<LoadResult> consumerInProgress,
            Consumer<List<ImageWrapper>> consumerDone
    ) {
        Task javafxTask = new Task<Void>() {
            @Override
            public Void call() {
                try {
                    ArrayList<ImageUtil.LoadResult> counter = new ArrayList<>();
                    double imageLength = imageFiles.size();
                    getForkJoinPool().submit(
                            () -> {
                                List<ImageWrapper> imageWrapperList = IntStream.range(0, imageFiles.size())
                                        .mapToObj(
                                                i -> {
                                                    File currentFile = imageFiles.get(i);
                                                    ImageWrapper imageWrapper = new ImageWrapper(
                                                            i,
                                                            currentFile,
                                                            null
                                                    );
                                                    return new LoadResult(imageWrapper);
                                                }
                                        )
                                        .filter(
                                                loadResult ->
                                                        !cachedImageWrapperList
                                                                .stream()
                                                                .anyMatch(
                                                                        (theImageWrapper)
                                                                                -> theImageWrapper.file == loadResult.imageWrapper.file
                                                                )
                                        )
                                        .parallel()
                                        .peek(
                                                loadResult -> {
                                                    loadResult.imageWrapper.image = getImageThumbnailFromFile(
                                                            loadResult.imageWrapper.file
                                                    );
                                                }
                                        )
                                        .peek(result -> {
                                            counter.add(result);
                                            result.progress = (double) counter.size() / imageLength;
                                            consumerInProgress.accept(result);
                                        })
                                        .filter(loadResult -> loadResult.imageWrapper.image != null)
                                        .sorted(
                                                Comparator.comparingInt((a) -> a.imageWrapper.index)
                                        )
                                        .map(loadResult -> loadResult.imageWrapper)
                                        .collect(Collectors.toList());
                                consumerDone.accept(imageWrapperList);
                            }
                    );
                } catch (Exception e) {
                    e.printStackTrace();
                }
                return null;
            }
        };
        Thread convertingThread = new Thread(javafxTask);
        convertingThread.setDaemon(true);
        convertingThread.start();
        return javafxTask;
    }
public static Task updateImageListParallel ( List < File > imageFiles , ArrayList < ImageWrapper > cachedImageWrapperList , Consumer < LoadResult > consumerInProgress , Consumer < List < ImageWrapper > > consumerDone ) { Task javafxTask = new Task < Void > ( ) { @ Override public Void call ( ) { try { ArrayList < ImageUtil . LoadResult > counter = new ArrayList < > ( ) ; double imageLength = imageFiles . size ( ) ; getForkJoinPool ( ) . submit ( ( ) -> { List < ImageWrapper > imageWrapperList = IntStream . range ( 0 , imageFiles . size ( ) ) . mapToObj ( i -> { File currentFile = imageFiles . get ( i ) ; ImageWrapper imageWrapper = new ImageWrapper ( i , currentFile , null ) ; return new LoadResult ( imageWrapper ) ; } ) . filter ( loadResult -> ! cachedImageWrapperList . stream ( ) . anyMatch ( ( theImageWrapper ) -> theImageWrapper . file == loadResult . imageWrapper . file ) ) . parallel ( ) . peek ( loadResult -> { loadResult . imageWrapper . image = getImageThumbnailFromFile ( loadResult . imageWrapper . file ) ; } ) . peek ( result -> { counter . add ( result ) ; result . progress = ( double ) counter . size ( ) / imageLength ; consumerInProgress . accept ( result ) ; } ) . filter ( loadResult -> loadResult . imageWrapper . image != null ) . sorted ( Comparator . comparingInt ( ( a ) -> a . imageWrapper . index ) ) . map ( loadResult -> loadResult . imageWrapper ) . collect ( Collectors . toList ( ) ) ; consumerDone . accept ( imageWrapperList ) ; } ) ; } catch ( Exception e ) { e . printStackTrace ( ) ; } return null ; } } ; Thread convertingThread = new Thread ( javafxTask ) ; convertingThread . setDaemon ( true ) ; convertingThread . start ( ) ; return javafxTask ; }
Create images in parallel with progress support in UI
 - Any generated images would be shown in UI immediately
Create images in parallel with progress support in UI - Any generated images would be shown in UI immediately
// run parallel task which will update main UI thread in JavaFX way // All generated images would be filtered out to reduce CPU computing // the place to report progress with the generated images // Done call back // make the thread and make it in background to not stop main UI thread