Java线程池的测试和分析

阅读更多

 

package cn.smallbug.jdk.concurrent.exe;

import java.io.Serializable;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.ThreadPoolExecutor.DiscardPolicy;
import java.util.concurrent.TimeUnit;

import org.junit.Before;
import org.junit.Test;

public class TestThreadPoolExecutor {

	private ThreadPoolExecutor pool = null;

	@Before
	public void before() {
		this.pool = new ThreadPoolExecutor(//
				/**
				 * corePoolSize(线程池的基本大小):
* 当提交一个任务到线程池时,线程池会创建一个线程来执行任务, * 即使其他空闲的基本线程能够执行新任务也会创建线程,等到需要执行的任务数大于线程池基本大小时就不再创建。 * 如果调用了线程池的prestartAllCoreThreads方法,线程池会提前创建并启动所有基本线程。 */ 10, /** * maximumPoolSize(线程池最大大小):
* 线程池允许创建的最大线程数。如果队列满了,并且已创建的线程数小于最大线程数,则线程池会再创建新的线程执行任务。 * 值得注意的是如果使用了无界的任务队列这个参数就没什么效果。 */ 20, /** * keepAliveTime(线程活动保持时间):
* 线程池的工作线程空闲后,保持存活的时间。 */ 1000, /** * TimeUnit(线程活动保持时间的单位):
* 可选:
*
    *
  • 单位有天(DAYS)
  • *
  • 小时(HOURS)
  • *
  • 分钟(MINUTES)
  • *
  • 毫秒(MILLISECONDS)
  • *
  • 微秒(MICROSECONDS, 千分之一毫秒)
  • *
  • 毫微秒(NANOSECONDS, 千分之一微秒)
  • *
*/ TimeUnit.MILLISECONDS, // 表示线程活动保持时间为1000ms, /** * runnableTaskQueue(任务队列):
* 用于保存等待执行的任务的阻塞队列。可以选择以下几个阻塞队列: *
    *
  • ArrayBlockingQueue:是一个基于数组结构的有界阻塞队列,此队列按 * FIFO(先进先出)原则对元素进行排序。
  • *
  • LinkedBlockingQueue:一个基于链表结构的阻塞队列,此队列按FIFO (先进先出) * 排序元素,吞吐量通常要高于ArrayBlockingQueue。静态工厂方法Executors. * newFixedThreadPool()使用了这个队列。
  • *
  • SynchronousQueue: * 一个不存储元素的阻塞队列。每个插入操作必须等到另一个线程调用移除操作, * 否则插入操作一直处于阻塞状态,吞吐量通常要高于LinkedBlockingQueue,静态工厂方法Executors. * newCachedThreadPool使用了这个队列。
  • *
  • PriorityBlockingQueue:一个具有优先级的无限阻塞队列。
  • *
*/ new ArrayBlockingQueue(100), /** * ThreadFactory:
* 用于设置创建线程的工厂,可以通过线程工厂给每个创建出来的线程设置更有意义的名字,Debug和定位问题时非常又帮助。 */ // new CreateThread(), /** * RejectedExecutionHandler(饱和策略):
* 当队列和线程池都满了,说明线程池处于饱和状态,那么必须采取一种策略处理提交的新任务。 * 这个策略默认情况下是AbortPolicy,表示无法处理新任务时抛出异常。以下是JDK1.5提供的四种策略 *
    *
  • CallerRunsPolicy:只用调用者所在线程来运行任务。
  • *
  • DiscardOldestPolicy:丢弃队列里最近的一个任务,并执行当前任务。
  • *
  • DiscardPolicy:不处理,丢弃掉。
  • *
  • 当然也可以根据应用场景需要来实现RejectedExecutionHandler接口自定义策略。 * 如记录日志或持久化不能处理的任务。
  • *
*/ new DiscardPolicy()// ); } /** * 线程池在创建时如果指定任务工厂execute的任务将无效 * * @timestamp Mar 19, 2016 3:08:56 PM */ @Test public void testExecute() { pool.execute(new Runnable() { @Override public void run() { System.out.println(2 + 2); } }); } /** * 线程池在创建时如果指定任务工厂execute的任务将无效 * * @timestamp Mar 19, 2016 3:11:21 PM */ @Test public void testSubmit() { int i = 100; while (i-- > 0) { pool.submit(// new Callable() { @Override public Serializable call() throws Exception { return 2 + 2; } }// ); } Future result = pool.submit(// new Callable() { @Override public Serializable call() throws Exception { return 2 + 2; } }// ); Serializable s = null; try { s = (int) result.get(); } catch (InterruptedException e) { // 处理中断异常 e.printStackTrace(); } catch (ExecutionException e) { // 处理无法执行任务异常 e.printStackTrace(); } finally { stastic(pool); /** * 1、将线程池的状态设置成SHUTDOWN状态
* 2、然后中断所有没有正在执行任务的线程 */ pool.shutdown(); /** * 1、将线程池的状态设置成STOP
* 2、遍历线程池中的工作线程
* 3、逐个调用线程的interrupt方法来中断线程(无法响应中断的任务可能永远无法终止)
* 4、返回等待执行任务的列表 */ // pool.shutdownNow(); /** * 只要调用了这两个关闭方法的其中一个,isShutdown方法就会返回true
* 当所有的任务都已关闭后,才表示线程池关闭成功,这时调用isTerminaed方法会返回true
* 通常调用shutdown来关闭线程池,如果任务不一定要执行完,则可以调用shutdownNow */ } System.out.println(s); } /** * 通过继承线程池并重写线程池的
* beforeExecute
* afterExecute
* terminated
* 方法,可以在任务执行前, 执行后和线程池关闭前干一些事情。如监控任务的平均执行时间,最大执行时间和最小执行时间等。 * * @timestamp Mar 19, 2016 3:37:29 PM * @param pool2 */ private void stastic(ThreadPoolExecutor pool) { System.out.println("current cpu num -> " + Runtime.getRuntime().availableProcessors()); System.out.println("线程池需要执行的任务数量 -> " + pool.getTaskCount()); System.out.println("线程池在运行过程中已完成的任务数量。小于或等于taskCount -> " + pool.getCompletedTaskCount()); System.out.println("线程池曾经创建过的最大线程数量 -> " + pool.getLargestPoolSize()); System.out.println("线程池的线程数量。如果线程池不销毁的话,池里的线程不会自动销毁,所以这个大小只增不减 -> " + pool.getPoolSize()); System.out.println("获取活动的线程数 -> " + pool.getActiveCount()); } /** * 工作任务创建工厂 * * @timestamp Mar 19, 2016 3:01:24 PM * @author smallbug */ class CreateThread implements ThreadFactory { @Override public Thread newThread(Runnable r) { return new Thread() { @Override public void run() { System.out.println(1 + 1); } }; } } }

 
          Java线程池的测试和分析_第1张图片

 

 

  1. 首先线程池判断基本线程池是否已满?没满,创建一个工作线程来执行任务。满了,则进入下个流程。
  2. 其次线程池判断工作队列是否已满?没满,则将新提交的任务存储在工作队列里。满了,则进入下个流程。
  3. 最后线程池判断整个线程池是否已满?没满,则创建一个新的工作线程来执行任务,满了,则交给饱和策略来处理这个任务。

参考博客:聊聊并发(三)Java线程池的分析和使用

  • Java线程池的测试和分析_第2张图片
  • 大小: 64.4 KB
  • 查看图片附件

你可能感兴趣的:(java,并发,线程池)