多线程处理pdf附件转换

业务中要把pdf转为pngs,作以下service

    public PageResult findByUrl(String url) {
        if(!Pdf2Img.checkPdf(url))
            return PageResult.genFail("非pdf文件");

        Attach attach = attachDao.findByUrl(url);

        if(attach == null) {
            AttachThread mt1=new AttachThread(url);
            new Thread(mt1).start();
            return PageResult.genFail("文件未准备好,请稍后再试");

        } else {
            String res = attach.getUrl_new();
            String [] imgs = res.split(",");
            return PageResult.genSuccess((Object)imgs);
        }
    }

传入pdf文件url,返回pngs文件url,

首先查找该附件有没有转过过,若转换过,直接返回转换后的url,若没转换过,新建线程进行转换

然而pdf转换png消耗资源及时间较大,若有两个线程同时请求转换,则会重复转换,浪费资源,故作同步处理如下:


public class AttachThread implements Runnable {

    private String url;
    private static AtomicInteger serailCount = new AtomicInteger(1);

    private Integer serial;

    public AttachThread(String _url) {
        url = _url;
        serial = serailCount.getAndIncrement();
    }

    @Override
    public void run(){
        AttachDao attachDao = (AttachDao)SpringUtil.getBean(AttachDao.class);
        Attach attach = attachDao.findByUrl(url);
        if(attach == null) {
            System.out.println(String.format("线程%d,类锁,所有线程阻塞", serial));
            synchronized (AttachThread.class) {
                attach = attachDao.findByUrl(url);
                if(attach == null) {
                    String url_new = Pdf2Img.comeGetIdList(url);

                    if(url_new != null || !"".equals(url_new)) {
                        attach = new Attach();
                        attach.setCreate_date(new Date());
                        attach.setUrl_old(url);
                        attach.setUrl_new(url_new);
                        attachDao.save(attach);
                    }
                    System.out.println(String.format("线程%d完成业务,释放类锁,第一线程应该走此路径", serial));
                } else {
                    System.out.println(String.format("线程%d取得锁之后发现业务已经处理,非第一线程应该走此路径", serial));
                }
            }
        } else {
            System.out.println(String.format("线程%d已经转换,不用锁,原则上不走此路径", serial));
        }
    }
}

AttachDao attachDao = (AttachDao)SpringUtil.getBean(AttachDao.class);

这一段是在此非spring托管的线程类中调用spring托管的类,详细见

http://blog.csdn.net/silyvin/article/details/70832415

http://www.cnblogs.com/vinozly/p/5223147.html


 Attach attach = attachDao.findByUrl(url);
        if(attach == null) {

如果没有找到转换后的png url,则开启转换程序

 System.out.println(String.format("线程%d,类锁,所有线程阻塞", serial));
            synchronized (AttachThread.class) {
                attach = attachDao.findByUrl(url);
                if(attach == null) {
                    String url_new = Pdf2Img.comeGetIdList(url);

                    if(url_new != null || !"".equals(url_new)) {
                        attach = new Attach();
                        attach.setCreate_date(new Date());
                        attach.setUrl_old(url);
                        attach.setUrl_new(url_new);
                        attachDao.save(attach);
                    }
                    System.out.println(String.format("线程%d完成业务,释放类锁,第一线程应该走此路径", serial));
                } else {
                    System.out.println(String.format("线程%d取得锁之后发现业务已经处理,非第一线程应该走此路径", serial));
                }
            }

开启同步,同步块中,第一线程,再次判断是否转换,其他线程阻塞


测试,同时进行4次请求,输出


线程1,类锁,所有线程阻塞

线程2,类锁,所有线程阻塞

线程3,类锁,所有线程阻塞

线程4,类锁,所有线程阻塞

线程1完成业务,释放类锁,第一线程应该走此路径

线程4取得锁之后发现业务已经处理,非第一线程应该走此路径

线程3取得锁之后发现业务已经处理,非第一线程应该走此路径

线程2取得锁之后发现业务已经处理,非第一线程应该走此路径






原文地址:https://www.cnblogs.com/silyvin/p/9106807.html