线程池ThreadPoolExecutor使用

1.  说明

     最近笔者在开发时,遇到了这样的问题。当笔者通过WEB界面删除某一条记录时,系统老是报“系统出错”,并且想到删除的数据并没有删除掉。查看Tomcat的日志,发现报了以下的错误:

 java.util.concurrent.RejectedExecutionException
	at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(Unknown Source)
	at java.util.concurrent.ThreadPoolExecutor.reject(Unknown Source)
	at java.util.concurrent.ThreadPoolExecutor.execute(Unknown Source)

如果对线程熟悉的读者,一眼就会知道,这样的错是跟线程有关系的,也就是说我在执行一条删除记录时,该删除代码被线程拒绝执行了。那就其了怪了,为什么好好的,线程会拒绝执行我的代码呢?通过跟踪代码,笔者发现,我们系统对于线程的处理都是难过线程池的调用的,也就是说当前的处理可能是超出线程池的大小,所以才被拒绝执行。好了,笔者知道了问题所在,修改了线程池的大小,果真问题解决了。但为了进行一步了解线程池,今天笔者就总结了一下线程池的用法。

2.  介绍ThreadPoolExecutor

      通过上面的报错信息,我们也就知道,线程池的类就是java.util.concurrent.ThreadPoolExecutor.通过源代码,我们可以看到这个方法的函数如下:

 public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              RejectedExecutionHandler handler) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             Executors.defaultThreadFactory(), handler);
    }
我们可以看到,总共有六个参数,那么这几个对数的作用如何呢?笔者通过下面的表格来说明:

这几个参数的作用,网上还给出了以下几点说明:

1)        如果线程池中运行的线程 小于corePoolSize ,即使线程池中的线程都处于空闲状态,也要 创建新的线程 来处理被添加的任务。

2)        如果线程池中运行的线程大于等于corePoolSize,但是缓冲队列 workQueue未满 ,那么任务被放入缓冲队列 。

3)        如果此时线程池中的数量大于corePoolSize,缓冲队列workQueue满(即无法将请求加入队列 ),并且线程池中的数量小于maximumPoolSize,建新的线程 来处理被添加的任务。

4)        如果此时线程池中的数量大于corePoolSize,缓冲队列workQueue满,并且线程池中的数量等于maximumPoolSize ,那么通过 handler 所指定的策略来处理此任务。

5)        当线程池中的线程数量大于corePoolSize时,如果某线程空闲时间超过keepAliveTime,线程将被终止 。这样,线程池可以动态的调整池中的线程数。

也就是说处理任务的优先级为:corePoolSize、任务队列workQueue、最大线程maximumPoolSize,如果三者都满了,使用handler处理被拒绝的任务。

在使用线程池时,经常会抛出这两个错误:IllegalArgumentException、NullPointerException。那么在什么情况下抛出IllegalArgumentException,又在什么情况下抛出NullPointerException错误呢?下面表格给出说明:


3.  例子说明

1)        首先,创建一个通用的线程池。这里主要就是new一个ThreadPoolExexutor的类,对于线程拒绝处理任务的处理,我们给出了两个方案,分别是:使用有界队列策略和使用无界队列策略。无界队列,我们使用LinkedBlockingQueue;有界队列是ArrayBlockingQueue.这里需要说明的是,使用无界queuw可能会耗尽系统资源,使用有界queue可能不能很好的满足性能,需要调用线程数和queue大小。

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * 创建线程池
 * 
 * @author owenwilliam
 * @Date 2017-4-17
 *
 */
public class ThreadPool
{

	public static final int ARRAY_QUEUE = 0; //ArrayBlockingQueue  有界队列策略
	public static final int LINKED_QUEUE = 1; //LinkedBlockingQueue 使用无界队列策略

	private ThreadPoolExecutor executor;
	private BlockingQueue<Runnable> workQueue;

	/**
	 * @param workQueneSize
	 *            队列长度
	 * @param coreSize
	 *            主线程数
	 * @param maxSize
	 *            最大线程数
	 * @param queueType
	 *            队列类型
	 */
	public ThreadPool(final int workQueneSize, final int coreSize,
			final int maxSize, int queueType)
	{
		this(workQueneSize, coreSize, maxSize, queueType, null);
	}

	/**
	 * 
	 * @param workQueneSize
	 *            队列长度
	 * @param coreSize
	 *            主线程数
	 * @param maxSize
	 *            最大线程数
	 * @param queueType
	 *            队列类型
	 * @param policy
	 *            处理策略
	 */
	public ThreadPool(final int workQueneSize, final int coreSize,
			final int maxSize, int queueType, RejectedExecutionHandler policy)
	{
		workQueue = createQueue(queueType, workQueneSize);
		executor = new ThreadPoolExecutor(coreSize, maxSize, 60,
				TimeUnit.SECONDS, workQueue, policy != null ? policy
						: new ThreadPoolExecutor.AbortPolicy());
	}

	public void execute(Runnable runnable)
	{
		if (workQueue.size() > 4)
		{
			
			System.out.println("当前等待线程大小:'"+runnable.getClass().getSimpleName()+
					         "':"+workQueue.size());
		}
		executor.execute(runnable);
	}

	/**
	 * 创建队列,选择不同和队列策略
	 * ArrayBlockingQueue  有界队列策略
	 * LinkedBlockingQueue 使用无界队列策略
	 * @param queueType
	 * @param queueSize
	 * @return
	 */
	private BlockingQueue<Runnable> createQueue(int queueType, int queueSize)
	{
		return queueType == LINKED_QUEUE ? new LinkedBlockingQueue<Runnable>(
				queueSize) : new ArrayBlockingQueue<Runnable>(queueSize);
	}

	public BlockingQueue<Runnable> getQueue()
	{
		return executor.getQueue();
	}
}

2)        创建一个线程。

 /**
 * 单个线程
 * @author owenwilliam
 * @Date 2017-4-17
 *
 */
public class ThreadRunnable implements Runnable
{

	String name;

	public ThreadRunnable(String name)
	{
		this.name = name;
	}

	@Override
	public void run()
	{
		// 处理一个任务,这里的处理方式太简单了,仅仅是一个打印语句
		System.out.println("start .." + name);
		try
		{
			// 便于观察,等待一段时间
			Thread.sleep(2000);
		} catch (Exception e)
		{
			e.printStackTrace();
		}

	}

}

3)        创建一个类调用线程池和线程。

/**
 * 使用线程池
 * 
 * @author owenwilliam
 * @Date 2017-4-17
 *
 */
public class USThreadPool
{

	private ThreadPool tp;
	private static USThreadPool pool = new USThreadPool();

	private USThreadPool()
	{
		int workQueneSize = 80;
		int coreSize = 4;
		int maxSize = 10;

		//创建线程池
		tp = new ThreadPool(workQueneSize, coreSize, maxSize,
				ThreadPool.ARRAY_QUEUE);
	}

	public static USThreadPool getPool()
	{
		return pool;
	}

	public void execute(Runnable runnable)
	{
		tp.execute(runnable);
	}

	public void execute(String name)
	{
		execute(new ThreadRunnable(name));
	}
}

4)        最后写一个测试类。

/**
 * 测试线程
 * 
 * @author owenwilliam
 * @Date 2017-4-17
 *
 */
public class TestThread
{

	public static void main(String[] args)
	{

		for (int i = 0; i < 10; i++)
		{

			USThreadPool.getPool().execute("num:" + i);
		}

	}

}

4.  执行结果



   

           源码地址:git@github.com:owenwilliam/ThreadPool.git



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java线程池ThreadPoolExecutorJava提供的一个用于管理和复用线程的工具类。它可以帮助我们更有效地管理线程资源,提高程序的性能和可维护性。 下面是一个简单的使用ThreadPoolExecutor的示例代码: ```java import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class ThreadPoolExample { public static void main(String[] args) { // 创建一个线程池,其中包含5个线程 ExecutorService executor = Executors.newFixedThreadPool(5); // 提交任务给线程池执行 for (int i = 0; i < 10; i++) { Runnable worker = new WorkerThread("Task " + i); executor.execute(worker); } // 关闭线程池 executor.shutdown(); while (!executor.isTerminated()) { // 等待所有任务完成 } System.out.println("所有任务已完成"); } } class WorkerThread implements Runnable { private String taskName; public WorkerThread(String taskName) { this.taskName = taskName; } @Override public void run() { System.out.println(Thread.currentThread().getName() + " 开始执行任务:" + taskName); try { // 模拟任务执行时间 Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + " 完成任务:" + taskName); } } ``` 上述代码中,首先通过`Executors.newFixedThreadPool(5)`创建了一个包含5个线程的线程池。然后使用`executor.execute(worker)`提交任务给线程池执行,其中`worker`是实现了`Runnable`接口的任务对象。任务会被线程池中的线程异步执行。 最后,通过`executor.shutdown()`关闭线程池,并使用`executor.isTerminated()`等待所有任务完成。完成后输出"所有任务已完成"。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值