多线程处理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取得锁之后发现业务已经处理,非第一线程应该走此路径