Fork-Join及Phaser

1、Fork-Join

fork/join是java7更新的一个新的轻量级任务执行框架,其主要目的是要更好滴利用底层平台上的多核CPU和多处理器来进行并行处理,解决问题时通常采用分治(divide and conquer)算法或map/reduce算法来进行。

fork操作是把一个大问题划分为若干较小的问题,一般是递归进行。

join操作是把部分解收集并组织起来,得到最终的完整解,也可能是递归进行的。

如果某个子问题由于等待另外一个子问题的完成而无法继续运行,那么处理该子问题的线程会主动寻找其他尚未运行的子问题来执行,减少了线程等待时间,提高了性能。

ForkJoinTask的子类:RecursiveTask(可返回结果)与RecursiveAction。

ForkJoinPool实现了ExecutorService接口。

public class ForkJoinDemo {

    private static final int RANGE_LENGTH = 2000;
    private final ForkJoinPool forkJoinPool = new ForkJoinPool();

    private static class MaxValueTask extends RecursiveTask<Long> {
        private final long[] array;
        private final int start;
        private final int end;

        MaxValueTask(long[] array, int start, int end) {
            this.array = array;
            this.start = start;
            this.end = end;
        }

        protected Long compute() {
            long max = Long.MIN_VALUE;
            if (end - start <= RANGE_LENGTH) {
                for (int i = start; i < end; i++) {
                    if (array[i] > max) {
                        max = array[i];
                    }
                }
            } else {
                int mid = (start + end) / 2;
                MaxValueTask lowTask = new MaxValueTask(array, start, mid);
                MaxValueTask highTask = new MaxValueTask(array, mid, end);
                lowTask.fork();
                highTask.fork();
                max = Math.max(max, lowTask.join());
                max = Math.max(max, highTask.join());
            }
            return max;
        }
    }

    public void calculate(long[] array) {
        MaxValueTask task = new MaxValueTask(array, 0, array.length);
        Long result = forkJoinPool.invoke(task);
        System.out.println(result);
    }

    public void calculateNormal(long[] array) {
        long max = Long.MIN_VALUE;
        for (int i = 0, n = array.length; i < n; i++) {
            if (array[i] > max) {
                max = array[i];
            }
        }
        System.out.println(max);
    }

    public static void main(String[] args) {
        Random random = new Random();
        int size = Integer.MAX_VALUE / 256;
        long[] array = new long[size];
        for (int i = 0; i < size; i++) {
            array[i] = random.nextLong();
        }
        ForkJoinDemo mv = new ForkJoinDemo();
        long startTime = System.currentTimeMillis();
        mv.calculate(array);
        long midTime = System.currentTimeMillis();
        System.out.println(midTime - startTime);
        mv.calculateNormal(array);
        long endTime = System.currentTimeMillis();
        System.out.println(endTime - midTime);
    }

}


这个例子,单从性能上比普通的方式要低很多,因为多线程带来的额外开销过大。但是fork/join可发挥作用的场景还是很多的,比如在目录里头的所有文本文件里头搜索某个关键词。



2、Phaser

Phaser类的特点是把多个线程协作执行的任务划分成多个阶段(phase),在每个阶段上都可以有任意个参与者参与。线程可以随时注册并参与到某个阶段的执行中来。当一个阶段中所有的线程都成功完成之后,Phaser类的对象会自动进入下一个阶段,如此循环下去,直到Phaser类的对象中不再包含任何参与者,此时它会自动结束。功能强大,可以替代CountDownLatch和CyclicBarrier。

Phaser的构造器可指定初始的参与者的个数。

(1)register

动态添加参与者


(2)arriveAndAwaitAdvance

完成之后等待其他参与者完成,会阻塞直到Phaser类的对象成功进入下一个阶段


(3)arriveAndDeregister

执行完成之后取消自己的注册,不参与下一个阶段的执行


public class PhaserDemo {

    private final Phaser phaser = new Phaser(1);
    private final Pattern imageUrlPattern = Pattern.compile("src=['\"]?(.*?(\\.jpg|\\.gif|\\.png))['\"]?[\\s>]+", Pattern.CASE_INSENSITIVE);
    public void download(URL url, final Path path, Charset charset) throws IOException {
        if (charset == null) {
            charset = StandardCharsets.UTF_8;
        }
        String content = getContent(url, charset);
        List<URL> imageUrls = extractImageUrls(content);
        for (final URL imageUrl : imageUrls) {
            phaser.register();
            new Thread() {
                public void run() {
                    //等待其他线程创建完成
                    phaser.arriveAndAwaitAdvance();
                    //进入图片下载阶段
                    try {
                        InputStream is = imageUrl.openStream();
                        Files.copy(is, getSavedPath(path, imageUrl), StandardCopyOption.REPLACE_EXISTING);
                    } catch (IOException e) {
                        e.printStackTrace();
                    } finally {
                        phaser.arriveAndDeregister();
                    }
                }
            }.start();
        }
        //等待其他下载线程创建完成
        phaser.arriveAndAwaitAdvance();
        //等待下载阶段的下载线程执行完成
        phaser.arriveAndAwaitAdvance();
        //下载完成之后注销自己
        phaser.arriveAndDeregister();
    }
    private String getContent(URL url, Charset charset) throws IOException {
        InputStream is = url.openStream();
        return IOUtils.toString(new InputStreamReader(is, charset.name()));
    }
    private List<URL> extractImageUrls(String content) {
        List<URL> result = new ArrayList<URL>();
        Matcher matcher = imageUrlPattern.matcher(content);
        while (matcher.find()) {
            try {
                result.add(new URL(matcher.group(1)));
            } catch (MalformedURLException e) {
                //忽略
            }
        }
        return result;
    }
    private Path getSavedPath(Path parent, URL url) {
        String urlString = url.toString();
        int index = urlString.lastIndexOf("/");
        String fileName = urlString.substring(index + 1);
        return parent.resolve(fileName);
    }

    public static void main(String[] args) throws IOException {
        URL url = new URL("http://www.baidu.com");
        PhaserDemo downloader = new PhaserDemo();
        downloader.download(url, Paths.get("imgs"), Charset.forName("GB2312"));
    }

}



转载于:https://my.oschina.net/scipio/blog/298409

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值