引入依赖

 <!-- 图片缩略图 --><dependency><groupId>net.coobird</groupId><artifactId>thumbnailator</artifactId><version>0.4.8</version></dependency><dependency><groupId>commons-io</groupId><artifactId>commons-io</artifactId><version>2.5</version></dependency>

全部代码,亲测可用


import com.sun.org.slf4j.internal.Logger;
import com.sun.org.slf4j.internal.LoggerFactory;
import net.coobird.thumbnailator.Thumbnails;
import org.apache.commons.io.FileUtils;import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class PicUtils1 {private static Logger logger = LoggerFactory.getLogger(PicUtils1.class);public static void main(String[] args) throws IOException {//图片文件夹路径String path = "D:\\photo\\a";List<String> filePath = getFilePath(path);ExecutorService taskExecutor  = Executors.newFixedThreadPool(30);final CountDownLatch latch = new CountDownLatch(filePath.size());//用于判断所有的线程是否结束System.out.println("a文件夹下面的图片总数"+filePath.size());for (int m = 0; m < filePath.size(); m++) {final int n = m;//内部类里m不能直接用,所以赋值给nRunnable run = new Runnable() {public void run() {try {byte[] bytes = FileUtils.readFileToByteArray(new File(filePath.get(n)));bytes = PicUtils1.compressPicForScale(bytes, 120);// 图片小于?FileUtils.writeByteArrayToFile(new File(filePath.get(n)), bytes);}catch (Exception e){e.printStackTrace();}finally {latch.countDown(); //每次调用CountDown(),计数减1}}};taskExecutor.execute(run);//开启线程执行池中的任务。还有一个方法submit也可以做到,它的功能是提交指定的任务去执行并且返回Future对象,即执行的结果}try {//等待所有线程执行完毕latch.await();//主程序执行到await()函数会阻塞等待线程的执行,直到计数为0} catch (InterruptedException e) {e.printStackTrace();}taskExecutor.shutdown();//关闭线程池//所有线程执行完毕,执行主线程}/*** 获取文件夹下所有文件的路径** @param folderPath* @return*/public static List<String> getFilePath(String folderPath) {File folder = new File(folderPath);List<String> filePathList = new ArrayList<>();String rootPath;if (folder.exists()) {String[] fileNameList = folder.list();if (null != fileNameList && fileNameList.length > 0) {if (folder.getPath().endsWith(File.separator)) {rootPath = folder.getPath();} else {rootPath = folder.getPath() + File.separator;}for (String fileName : fileNameList) {filePathList.add(rootPath + fileName);}}}return filePathList;}/*** 根据指定大小压缩图片** @param imageBytes  源图片字节数组* @param desFileSize 指定图片大小,单位kb* @return 压缩质量后的图片字节数组*/public static byte[] compressPicForScale(byte[] imageBytes, long desFileSize) {if (imageBytes == null || imageBytes.length <= 0 || imageBytes.length < desFileSize * 1024) {return imageBytes;}long srcSize = imageBytes.length;double accuracy = getAccuracy(srcSize / 1024);try {while (imageBytes.length > desFileSize * 1024) {ByteArrayInputStream inputStream = new ByteArrayInputStream(imageBytes);ByteArrayOutputStream outputStream = new ByteArrayOutputStream(imageBytes.length);Thumbnails.of(inputStream).scale(accuracy).outputQuality(accuracy).toOutputStream(outputStream);imageBytes = outputStream.toByteArray();}System.out.println("图片原大小(kb):"+  srcSize / 1024);System.out.println("压缩后大小(kb):"+imageBytes.length / 1024);} catch (Exception e) {logger.error("【图片压缩】msg=图片压缩失败!", e);}return imageBytes;}/*** 自动调节精度(经验数值)** @param size 源图片大小* @return 图片压缩质量比*/private static double getAccuracy(long size) {double accuracy;if (size < 900) {accuracy = 0.85;} else if (size < 2047) {accuracy = 0.6;} else if (size < 3275) {accuracy = 0.44;} else {accuracy = 0.4;}return accuracy;}}

使用线程池的方式压缩图片相关推荐

  1. Java创建线程池的方式

    Java创建线程池的方式 文章目录 Java创建线程池的方式 一.通过Executors工厂方法创建 1.Executors.newSingleThreadExecutor() 2.Executors ...

  2. 手把手教你线程池配合CompletableFuture实现图片下载并压缩

    你知道的越多,不知道的就越多,业余的像一棵小草! 成功路上并不拥挤,因为坚持的人不多. 编辑:业余草 juejin.cn/post/6976454072685559822 推荐:https://www ...

  3. Android通过AsyncTask与ThreadPool(线程池)两种方式异步加载大量数据的分析与对比

    在加载大量数据的时候,经常会用到异步加载,所谓异步加载,就是把耗时的工作放到子线程里执行,当数据加载完毕的时候再到主线程进行UI刷新.在数据量非常大的情况下,我们通常会使用两种技术来进行异步加载,一是 ...

  4. Android 应用开发 之通过AsyncTask与ThreadPool(线程池)两种方式异步加载大量数据的分析与对比

    Android 应用开发 之通过AsyncTask与ThreadPool(线程池)两种方式异步加载大量数据的分析与对比 标签: AndroidAsyncTaskThreadPool异步加载view 2 ...

  5. 关于线程池的五种实现方式,中软国际Java机试

    在这里,还有创建一个只有单个线程的可以定时执行线程池(Executors.newSingleThreadScheduledExecutor())这些都是上面的线程池扩展开来了,不详细介绍了. 3 介绍 ...

  6. java线程三种创建方式与线程池的应用

    前言:多线程下程序运行的结果是随机的,以下案例代码的运行结果仅供参考 一 通过继承Thread线程创建的方法与执行的步骤 /* 1 继承Thread 2重写run方法 3创建线程继承类的子类 4 调用 ...

  7. 多线程、线程池的创建方式,为什么阿里推荐自定义线程池?

    1.多线程的四种实现方式 * 多线程的实现方式有四种* 1.继承thread类* 2.实现runnable接口* 3.实现Callable* 实现Callable不能简单把Callable对象传给th ...

  8. 从源码分析创建线程池的4种方式

    摘要:从创建线程池的源码来深入分析究竟有哪些方式可以创建线程池. 本文分享自华为云社区<[高并发]从源码角度分析创建线程池究竟有哪些方式>,作者:冰 河 . 在Java的高并发领域,线程池 ...

  9. 为什么阿里不允许用Executors创建线程池,而是通过ThreadPoolExecutor的方式?

    1.通过Executors创建线程池的弊端 在创建线程池的时候,大部分人还是会选择使用Executors去创建. 下面是创建定长线程池(FixedThreadPool)的一个例子,严格来说,当使用如下 ...

最新文章

  1. 栈和队列互相实现,一文弄懂它们的关系
  2. Dictionary里使用struct,enum做key
  3. Angular里的按钮事件注册方法一例
  4. 飞鸽传书mayfish 数据入库验证
  5. Socket编程实践(6) --TCP服务端注意事项
  6. .Net水晶报表的使用总结
  7. 判断字符串是否是有效的手机号码
  8. javaweb:域对象的属性操作setAttribute(),getAttribute()及其作用范围
  9. 软件易用性文章分享 ● 第一篇
  10. python过滤器_python中的Butterworth过滤器
  11. Real Time Transfer (RTT)
  12. itan:request-response简介
  13. 友价商城2019.2月最新版
  14. 派森学python_2019 年 1月 26 日 随笔档案 - 派森学python - 博客园
  15. 因果推断——现代统计的思想飞跃
  16. Android Studio制作简易微信界面
  17. 康涅狄格大学计算机科学排名,康涅狄格大学排名计算机科学,必须注意考察
  18. 【移动开发】2022 年 12 大移动应用程序开发趋势
  19. 删除oracle备份日志,TSM备份oracle归档日志,过期删除问题
  20. Cola公司的雇员分为以下若干类:(知识点:多态) 4.1 ColaEmployee :这是所有员工总的父类,属性:员工的姓名,员工 的生日月份。方法:getSalary(int month) 根据

热门文章

  1. HTML5 之 Fieldset 标签
  2. 【调剂】北方工业大学信息学院2022年硕士研究生复试录取办法
  3. ubunntu系统网页无法播放视频解决办法
  4. Delphi for iOS开发指南(14):在iOS应用程序中使用InterBase ToGo
  5. 【MDM ‘19】Learned Index for Spatial Queries
  6. diea 创建 maven 工程
  7. Codeforces Round #748 E. Gardener and Tree
  8. CentOS的u盘安装有u盘才启动,没有u盘无法启动的解决方法by 42coder
  9. 【USACO 2.4.4】回家
  10. 清华镜像快速下载包方法