以前写了一篇文章关于四种线程池的解析。
可是对于FixedThreadPool与CachedThreadPool适用的场景其实仍是比较模糊难以界定的。因此笔者今天经过设计大任务并发和小任务并发来验证FixedThreadPool与CachedThreadPool的适用场景。
首先我设计了一个任务基类,它经过计算圆周率来模拟cpu的密集计算、经过写日志到本地文件来模拟IO。
这两个方法都经过参数n来调整任务的大小规模。html
public class Task { /** * 经过计算圆周率模拟cpu计算 * 经过公式 π=4*(1-1/3+1/5-1/7+1/9-1/11+....) * * @return */ public static double calculatePI(long n) { double item = 0.0; double sum = 0; int flag = -1; for (int i = 0; i <= n; i++) { flag *= -1; item = flag * 1.0 / (2 * i + 1); sum += item; } return sum * 4; } /** * 经过写日志模拟IO操做 * @param n */ public static void writeIO(int n) { try { Date date = new Date(); SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss-SSS"); String fileName = Thread.currentThread().getName() + "-" + format.format(date) + ".log"; FileOutputStream os = new FileOutputStream("C:\\Users\\valarchie\\Desktop\\logs\\" + fileName); for (int i = 0; i < n; i++) { os.write(("写入日志" + i + "次").getBytes()); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }
在笔者的设计当中大任务的规模是小任务的10倍,具体请看代码:多线程
大任务:并发
public class BigTask extends Task implements Runnable { private CountDownLatch latch; public BigTask(CountDownLatch latch) { this.latch = latch; } public static double calculatePI() { return calculatePI(100000000); } public static void writeIO() { writeIO(100); } @Override public void run() { calculatePI(); writeIO(); latch.countDown(); } }
小任务:ide
public class SmallTask extends Task implements Runnable { private CountDownLatch latch; public SmallTask(CountDownLatch latch) { this.latch = latch; } public static double calculatePI() { return calculatePI(10000000); } public static void writeIO() { writeIO(10); } @Override public void run() { calculatePI(); writeIO(); latch.countDown(); } }
经过测试咱们得出一个小任务的运行时间大概在86ms左右。一个大任务的运行时间大概在575ms左右。
接下来咱们分别测试100个大任务和100个小任务分别在单线程、FixedThreadPool、CachedThreadPool三种状况下的运行时间(个人笔记本是4核的,通过简单测试FixedThreadPool在16线程数的状况下性能最优良)。性能
咱们使用CountDownLatch的计算多线程的运行时间,如下是多线程的测试代码模板:测试
public static void main(String[] args) { int taskCount = 100; CountDownLatch latch = new CountDownLatch(taskCount); ExecutorService executorService = Executors.newFixedThreadPool(16); long t1 = System.currentTimeMillis(); for (int i = 0; i < taskCount; i++) { executorService.submit(new SmallTask(latch)); } try { latch.await(); } catch (InterruptedException e) { e.printStackTrace(); } long t2 = System.currentTimeMillis(); // 得出多线程的运行时间 System.out.println(t2 - t1); executorService.shutdown(); }
任务模型*100 | 单线程 | FixedThreadPool | CachedThreadPool |
---|---|---|---|
大任务 | 45067ms | 6613ms | 6224ms |
小任务 | 4754ms | 722ms | 726ms |
经过统计发现多线程的性能比单线程的性能优异不少,可是其实FixedThreadPool和CachedThreadPool的性能差别是差很少相等的并无比较大差异。this
为了更严谨一点,咱们控制任务方法的规模和任务数量的规模再进行一次测试线程
任务模型*100 | FixedThreadPool | CachedThreadPool |
---|---|---|
大任务方法规模*10 | 78738ms | 79669ms |
大任务数量规模*10 | 73654ms | 69343ms |
笔者通过验证得出的结论是两种线程池其实在性能上没有很是大差异,可是FixedThreadPool能够控制线程的并发数量,而CachedThreadPool不能控制线程的并发数量。若是线程数量爆发增加的话对系统会带来危害。我的认为使用FixedThreadPool会更好。设计