java线程池学习(二) —— 实现一个简单的线程池

在上一篇文章中《java线程池学习(一) —— BlockingQueue》,我们简单探讨了一下BlockingQueue的概念。

那么在这边文章,我们要利用BlockingQueue来自己实现一个简单的线程池,在以后的章节中,我们再学习一下怎么去使用java为我们封装好的线程池。

首先我们关注一个 “生产者消费者” 的情景。

生产者:不断产生新的需要解决的任务,比如查询数据库,执行某些业务逻辑等。

消费者:不断解决产生的问题。

那么把这两者连接起来的就要用到我们的BlockingQueue了。

生产者将不断产生的任务放入到队列中,如果队列满了,生产者等待。

消费者不断的从队列中取出任务解决,当队列空了,消费者等待新任务到来。

首先BlockQueue的长度我们要限制,不然如果解决者的解决能力跟不上生产者的,这个任务队列就会越来越多。

接着我们还需要限定问题解决者的个数,就是我们所谓的线程池中能同时运行的最多的线程数,如果线程数太多的话会严重影响系统的稳定性。

那么我们根据这两个参数写一个简单的线程池:

线程池:

public class ThreadPool {
	//用blockingQueue创建一个任务队列,初始化长度为5
	private BlockingQueue<Runnable> tasksQueue = new ArrayBlockingQueue<Runnable>(5);
	//定义线程池中消费者最大数量
	private int consumers = 3;
	
	//这个方法提供给所有的任务生产者,产生新的任务插入
	public void insertTask(Runnable task) throws InterruptedException{
		tasksQueue.put(task);
	}
	
	//线程池的初始化
	ThreadPool(){
                //激活消费者,等待问题到来
		for(int i=1;i<=consumers;i++){
			Solver consumer = new Solver(tasksQueue,i);
			consumer.start();
		}
	}
}

接下来定义 消费者 逻辑:

public class Solver extends Thread{
	
	//引用线程池的任务队列,消费者不断的从里面取得任务去解决
	private BlockingQueue<Runnable> taskQueue = null;
	
	String name;
	
	Solver(BlockingQueue<Runnable> tasks,int name){
		this.taskQueue = tasks;
		this.name = String.valueOf(name);
	}
	
	public void run(){
		try {
			while(true){
				//从队列中取出任务执行,注意这里用了take方法,所以如果队列空了,那么线程会等待,直到有任务来了,继续执行
				Runnable task = taskQueue.take();
				System.out.println("消费者"+name+"接收了一个任务");
				task.run();
				System.out.println("消费者"+name+"解决了一个任务");
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
}

我们在上面的例子可以看到。

这个线程池中最大的线程数是3,就是最多只能同时有3个消费者线程执行,消费者会监视线程池的任务队列,只要队列中有任务,就会取出来执行。

接下来我们定义 生产者 的逻辑:

public class ProblemCreater {

	public static void main(String[] args) throws Exception {
		//初始化线程池
		ThreadPool threadPool = new ThreadPool();
		
		//生成者不断产生任务
		for(int i=1;i<10;i++){
			
			//定义一个新的任务
			Runnable task = new Runnable(){
				public void run(){
					Random random = new Random();
					//随机一个数字模拟需要解决的时间
					int randomTime = Math.abs(random.nextInt())%20;
					//System.out.println("这个任务需要解决时间为:"+randomTime);
					try {
						Thread.sleep(randomTime*1000);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			};
			//将问题插入到线程池任务队列中
			threadPool.insertTask(task);
			System.out.println("插入新的任务"+i);
		}
	}

}


到此我们已经实现好了一个非常简单的线程池,将线程的创建与执行过程分离开,而不是将线程的生命周期管理和任务的执行过程绑定在一起,如果只是想简单的丢一个任务进去执行,我们只需要将任务的执行过程封装到一个Runnable接口中就可以了。而对于那些需要返回结果的任务,我们可以将其封装到Callable接口里面。

当然java线程池比我们自己写的这个高大上很多,在以后的篇幅中,我们再做具体研究。



  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值