Java并发代码改进思路

时间:2016-07-05 20:48:52

标签: java concurrency

我最近对Java并发任务进行了编码访谈,但遗憾的是没有得到这份工作。最糟糕的是我尽力而为,但现在我甚至不确定哪里出了问题。任何人都可以帮我一些关于我可以在下面的代码上改进的东西的想法吗?感谢

这个问题很模糊。给定4个通用接口,在高层次上将任务分成小块,处理每个部分并将部分结果组合成最终结果,我被要求实现接口的中央控制器部分。唯一的要求是在部分结果处理中使用并发性,“代码必须是生产质量”

我的代码如下(给出了接口)。我确实做了很多评论来解释我在这里删除的假设

// adding V,W in order to use in private fields types
public class ControllerImpl<T, U, V, W> implements Controller<T, U> {

    private static Logger logger = LoggerFactory.getLogger(ControllerImpl.class);

    private static int BATCH_SIZE = 100;

    private Preprocessor<T, V> preprocessor;
    private Processor<V, W> processor;
    private Postprocessor<U, W> postprocessor;

    public ControllerImpl() {
        this.preprocessor = new PreprocessorImpl<>();
        this.processor = new ProcessorImpl<>();
        this.postprocessor = new PostprocessorImpl<>();
    }

    public ControllerImpl(Preprocessor preprocessor, Processor processor, Postprocessor postprocessor) {
        this.preprocessor = preprocessor;
        this.processor = processor;
        this.postprocessor = postprocessor;
    }

    @Override
    public U process(T arg) {
        if (arg == null) return null;

        final V[] parts = preprocessor.split(arg);
        final W[] partResult = (W[]) new Object[parts.length];

        final int poolSize = Runtime.getRuntime().availableProcessors();  
        final ExecutorService executor = getExecutor(poolSize);

        int i = 0;
        while (i < parts.length) {
            final List<Callable<W>> tasks = IntStream.range(i, i + BATCH_SIZE)
                .filter(e -> e < parts.length) 
                .mapToObj(e -> (Callable<W>) () -> partResult[e] = processor.processPart(parts[e])) 
                .collect(Collectors.toList());
            i += tasks.size();

            try {
                logger.info("invoking batch of {} tasks to workers", tasks.size());
                long start = System.currentTimeMillis();
                final List<Future<W>> futures = executor.invokeAll(tasks); 
                long end = System.currentTimeMillis();
                logger.info("done batch processing took {} ms", end - start);
                for (Future future : futures) {
                    future.get();
                }
            } catch (InterruptedException e) {
                logger.error("{}", e);// have comments to explain better handling according to real business requirement 
            } catch (ExecutionException e) {
                logger.error("error: ", e);
            }
        }

        MoreExecutors.shutdownAndAwaitTermination(executor, 60, TimeUnit.SECONDS);

        return postprocessor.aggregate(partResult);
    }

    private ExecutorService getExecutor(int poolSize) {
        final ThreadFactory threadFactory = new ThreadFactoryBuilder()
            .setNameFormat("Processor-%d")
            .setDaemon(true)
            .build();
        return new ThreadPoolExecutor(poolSize, poolSize, 60, TimeUnit.SECONDS, new LinkedBlockingDeque<>(), threadFactory);
    }
}

1 个答案:

答案 0 :(得分:5)

因此,如果我理解正确,你有一个预处理器,它接受一个T并将其拆分为一个V []数组。然后你有一个处理器,它将V转换为W.然后是一个后处理器,它将W [转换为U,对吗?你必须组装这些东西。

首先,数组和泛型实际上并不匹配,因此这些方法返回数组而不是列表真的很奇怪。对于生产质量的代码,不应使用通用数组。

所以,回顾一下:

T --> V1 --> W1 --> U
      V2 --> W2
      .      .
      .      .
      Vn --> Wn

所以你可以这样做:

V[] parts = preprocessor.split(t);
W[] transformedParts = 
    (W[]) Arrays.stream(parts) // unchecked cast due to the use of generic arrays
                .parallel() // this is where concurrency happens
                .map(processor::processPart)
                .toArray();
U result = postProcessor.aggregate(transformedParts);

如果您使用列表而不是数组,并将其写为一行:

U result = 
    postProcessor.aggregate(
        preprocessor.split(t)
                    .parallelStream()
                    .map(processor::processPart)
                    .collect(Collectors.toList()));