将多线程输出馈送到现代Java中的单线程的惯用方式?

时间:2019-04-06 21:14:03

标签: java multithreading thread-safety java-stream forkjoinpool

我有此代码,可以正常工作。这个问题的重点是代码的可维护性,减少编写代码即可实现相同的目标:

                Queue<IncomingItem[]> queue = new ConcurrentLinkedQueue<>();
                IncomingItem[] EOF = new IncomingItem[0];

                ForkJoinPool.commonPool().submit(() -> {
                    IncomingItem[] next;
                    while((next = queue.poll()) != EOF) {
                        if(next == null) {
                            try {
                                Thread.sleep(1000);
                            } catch (InterruptedException e) {
                                throw new RuntimeException(e);
                            }
                            continue;
                        }
                        dao.batchInsert(next);
                    }
                });
                ds.reload(queue::add);
                queue.add(EOF);
                ForkJoinPool.commonPool().awaitQuiescence(1, TimeUnit.HOURS);

目的是使ds.reload(这是一个多线程方法)的输出被馈送到dao.batchInsert方法中,该方法是非线程安全的,非线程共享的(例如,一个基于Hibernate的DAO),而不会阻塞ds.reload方法,就像将dao.batchInsert方法设为synchronized一样。

此代码与Java 8兼容。较新的Java版本中有什么可以实现更优雅的解决方案的东西吗?

1 个答案:

答案 0 :(得分:1)

在这里使用线程池是不必要的麻烦。使用专用线程。与其轮询和休眠,不如使用阻塞队列。

            BlockingQueue<IncomingItem[]> queue = new LinkedBlockingQueue<>();
            IncomingItem[] EOF = new IncomingItem[0];
            Thread thread = new Thread(() -> {
                IncomingItem[] next;
                while((next = queue.take()) != EOF) {
                    dao.batchInsert(next);
                }
            });
            thread.start();
            ds.reload(queue::put);
            queue.add(EOF);
            thread.join();