多线程学习笔记十二——Fork/Join框架的使用

案例场景:把pdf转成图片,客户上传pdf,然后用图片再展示给客户,因为pdf展示过大过慢,所以提高pdf转图片的快慢会严重影响到请求相应的速度,此案例使用了俩页pdf为任务的最小单元,具体代码如下:

package com.zqsign.file.external.utils;

import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.Future;
import java.util.concurrent.RecursiveTask;
import java.util.concurrent.atomic.AtomicInteger;

import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.rendering.PDFRenderer;
import org.apache.pdfbox.tools.imageio.ImageIOUtil;

/**
    * @ClassName: PdfConvertImgTask
    * @Description: pdf转图片
    * @author shidebin
    * @date 2018年9月7日
    *
    */

public class PdfConvertImgTask extends RecursiveTask<Integer>{
    private static final long serialVersionUID = 1L;
    private static final int THRESHOLD = 2;// 阈值
    private int start;
    private int end;
    //private ThreadLocal<byte[]> ThreadLocal = new ThreadLocal<>();
    private byte[] fileBytes;
    private AtomicInteger num = null;

    public PdfConvertImgTask(int threadnum,int start, int end,byte[] fileBytes) {
        this.start = start;
        this.end = end;
        //ThreadLocal.set(fileBytes);
        this.fileBytes = fileBytes;
        num = new AtomicInteger(threadnum);
    }
    public PdfConvertImgTask(int start, int end,byte[] fileBytes) {
        this.start = start;
        this.end = end;
        //ThreadLocal.set(fileBytes);
        this.fileBytes = fileBytes;
    }
    public PdfConvertImgTask(int start, int end) {
        this.start = start;
        this.end = end;
    }

     /**
      * @Title: compute
      * @Description: pdf转图片
      * @param @return    参数
      * @author shidebin
      * @date 2018年9月7日
      * @throws
      */

    @Override
    protected Integer compute() {
        int sum = 0;
        // 如果任务足够小就计算任务
        boolean canCompute = (end - start) <= THRESHOLD;
        if (canCompute) {
                PDDocument doc = null;
                List<String> imgURIs = new ArrayList<String>();
                try {
                    String imgURI = null;// 图片地址
                   // doc = PDDocument.load(ThreadLocal.get());
                    doc = PDDocument.load(fileBytes);
                    PDFRenderer pdfRenderer = new PDFRenderer(doc);
                    byte[] fileByte = null;
                    FileOutputStream file = null;
                    File file1 = null;
                    for (int page = start; page < end; ++page) {
                        ByteArrayOutputStream os = new ByteArrayOutputStream();
                        BufferedImage bim = pdfRenderer.renderImageWithDPI(page, 150F);
                        ImageIOUtil.writeImage(bim, "JPG", os);
                        try {
                            fileByte = os.toByteArray();
                            file1 = new File("D:/imgs/"+num.get());
                            if(!file1.exists()) {
                                file1.mkdir();
                            }
                            file = new FileOutputStream("D:/imgs/"+num.get()+"/"+page+".JPG");
                            file.write(fileByte);
                        } finally {
                            if (os != null) {
                                os.close();
                            }
                            if (file != null) {
                                file.close();
                            }
                        }
                        imgURIs.add(imgURI);
                        sum++;
                    }

                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    if (doc != null)
                        try {
                            doc.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                }
        } else {
            // 如果任务大于阈值,就分裂成两个子任务计算
            int middle = (start + end) / 2;
            PdfConvertImgTask leftTask = new PdfConvertImgTask(num.get(),start, middle,fileBytes);
            PdfConvertImgTask rightTask = new PdfConvertImgTask(num.get(),middle + 1, end,fileBytes);
            // 执行子任务
            leftTask.fork();
            rightTask.fork();
            // 等待子任务执行完,并得到其结果
            int leftResult = leftTask.join();
            int rightResult = rightTask.join();
            // 合并子任务
            sum = leftResult + rightResult;
        }
        return sum;
    }

    public static void main(String[] args) {
        for(int i = 0;i<10;i++) {
            new Thread(""+i){
                public void run() {
                    ForkJoinPool forkJoinPool = new ForkJoinPool();
                    long start = System.nanoTime();
                    File file = new File("D:/Java并发编程的艺术.pdf");
                    byte[] fileBytes = null;
                    int pageSize = 0;
                    PDDocument doc = null;
                    try {
                        fileBytes = org.apache.commons.io.IOUtils.toByteArray(new FileInputStream(file));
                        doc = PDDocument.load(fileBytes);
                        pageSize = doc.getNumberOfPages();
                        doc.getPages();
                        System.out.println(Thread.currentThread().getName()+"========"+pageSize);
                    } catch (FileNotFoundException e) {
                        e.printStackTrace();
                    } catch (IOException e) {
                        e.printStackTrace();
                    } finally {
                        if (doc != null)
                            try {
                                doc.close();
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                    }
                    // 生成一个计算任务,负责计算1+2+3+4
                    PdfConvertImgTask task = new PdfConvertImgTask(Integer.parseInt(Thread.currentThread().getName()),0, pageSize, fileBytes);
                    // 执行一个任务
                    Future<Integer> result = forkJoinPool.submit(task);
                    if(task.isCompletedAbnormally()) {
                        try {
                            throw task.getException();
                        } catch (Throwable e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                    }
                    try {
                        System.out.println(Thread.currentThread().getName()+"========"+result.get());
                        System.out.println(Thread.currentThread().getName()+"========"+(System.nanoTime() - start));
                    } catch (InterruptedException e) {
                    } catch (ExecutionException e) {
                    }
                }
            }.start();
        }

    }

}

此案例使用pdf为422,启用了10线程进行转图片,总共运行时间不到2分钟,运行结果如图:
十个线程转成的图片文件
其中一个线程转成的图片内容
使用到pdf转图片的pom文件的配置:

<dependency>
        <groupId>org.apache.pdfbox</groupId>
        <artifactId>pdfbox</artifactId>
        <version>2.0.5</version>
</dependency>

猜你喜欢

转载自blog.csdn.net/shidebin/article/details/82658778