线程学习笔记(十二)-线程池

线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务。线程池线程都是后台线程,每个线程都使用默认的堆栈大小,以默认的优先级运行,并处于多线程单元中。本实例介绍如何运用线程池实现任务的执行。
技术要点
运用线程池实现任务的执行的技术要点如下:
如果某个线程在托管代码中空闲,则线程池将插入另一个辅助线程(线程池)来使所有处理器保持繁忙;如果所有线程池线程都始终保持繁忙,但队列中包含挂起的工作,则 线程池将在一段时间后创建另一个辅助线程(线程池),但线程的数目永远不会超过最大值。超过最大值的线程可以排队,但它们要等到其他线程完成后后才启动。
任务放在LinkedList中,由于LinkedList不支持同步,所以在添加任务和获取任务的方法声明中必须使用synchronized关键字
关闭线程池时,通过ThreadGroup线程组获得池中所有活动线程的引用,依次调用Thread类的join()方法等待活动线程执行完毕。当所有线程运行结束是,线程池才算被关闭。
package core;

import java.util.LinkedList;

class ThreadPool extends ThreadGroup {
	private static int threadPool_ID = 1; // 线程池的编号
	private LinkedList<Runnable> taskQueue; // 工作任务队列
	private boolean isClosed = false;// 线程池是否关闭

	private class TaskThread extends Thread {
		private int id;

		public TaskThread(int id) {
			super(ThreadPool.this, id + "");// 将线程加入到当前线程组中
			this.id = id;
		}

		public void run() {
			while (!isInterrupted()) {// 判断线程是否被中断
				Runnable task = null;
				task = getTask(id);// 取出任务
				// 如果getTask()返回null或者线程执行getTask()被中断,则结束此线程
				if (task == null)
					return;
				try {
					task.run(); // 运行任务
				} catch (Throwable t) {
					t.printStackTrace();
				}

			}
		}
	}

	public synchronized Runnable getTask(int id) {
		try {
			while (taskQueue.size() == 0) {// 循环使线程等待任务
				if (isClosed)
					return null;
				System.out.println("工作线程" + id + "等待任务");
				wait();// 如果任务队列中没有任务,就等待任务
			}
		} catch (InterruptedException e) {
			System.out.println("等待任务出现错误: " + e.getMessage());
		}
		System.out.println("工作线程" + id + "开始执行任务。。。。");
		return (Runnable) taskQueue.removeFirst();// 返回第一个任务并从队列中删除
	}

	public ThreadPool(int poolsize) {
		super(threadPool_ID + " ");
		setDaemon(true);
		taskQueue = new LinkedList<Runnable>();// 创建工作任务队列
		for (int i = 0; i < poolsize; i++) {// 循环创建任务线程
			new TaskThread(i).start();//根据线程池数据创建任务线程并启动线程
		}
	}
	public   synchronized void exexcuteTask(Runnable task){//添加新任务并执行任务
		if(isClosed){
			throw new IllegalStateException();//抛出不合理状态异常
		}
		if(task !=null){
			taskQueue.add(task);//向任务队列中加入一个任务
			notify();//唤醒线程池中等待任务的工作任务线程
		}
	}
	public void waitTaskFinish(){
		synchronized(this){
			isClosed=true;
			notifyAll();//唤醒所有等待任务的工作任务线程
		}
		Thread[] threads=new Thread[activeCount()];//创建线程组中活动的线程组
		int count=enumerate(threads);//获得线程组中当前所有活动的工作线程
		for (int i = 0; i < count; i++) {
			try {
				threads[i].join();
			} catch (InterruptedException e) {
				System.out.println("任务执行出错: " + e.getMessage());

			}
		}
	}
	public synchronized void closeThreadPool(){//关闭线程池
		if(!isClosed){    //判断标识
			waitTaskFinish();  //等待任务线程执行完毕
			isClosed=true;   //标识为真
			taskQueue.clear();//任务队列清空
			interrupt();//唤醒线程池中所有的工作线程
		}
	}
}

public class TextThreadPool {
	private static Runnable createTask(final int taskID) {// 创建任务方法
		return new Runnable() {
			@Override
			public void run() {
				System.out.println("任务开始,编号为" + taskID);
				System.out.println("start task");
				System.out.println("任务结束,编号为" + taskID);
			}
		};
	}

	public static void main(String[] args) {
		ThreadPool threadPool=new ThreadPool(3); //初始化创建3个任务线程的线程池,等待执行任务
		try {//休眠600毫秒,让线程池中的任务线程全部运行
			Thread.sleep(600);
		} catch (InterruptedException e) {
			System.out.println("线程休眠出错: "+e.getMessage());
		}
		for (int i = 0; i < 5; i++) { //循环创建并执行任务
			threadPool.exexcuteTask(createTask(i));
		}
		threadPool.waitTaskFinish();//等待所有任务执行完毕
		threadPool.closeThreadPool();//关闭线程池
	}
}


源程序解读
(1)TextThreadPool类的createTask()方法根据任务编号执行指定的任务。在类的main()主方法中实例化三个ThreadPool对象作为线程池,Thread类的sleep()方法使线程休眠0.6秒,运用循环执行创建的工作任务,如果没有创建工作任务,则线程池的三个ThreadPool则会一直等待,调用waitTaskFinish()方法等待所有的任务执行完毕再关闭线程池。
(2)内部类ThreadPool继承线程组类ThreadGroup实现线程池的功能。其私有内部类TaskThread继承Thread线程类,扩展run()方法。在run()方法中根据标识为真进行循环。根据Thread类的getTask()方法获得Runnable任务对象,调用任务对象的run()方法执行任务。
(3)ThreadPool类的构造方法传入线程池中工作线程的数量,设置该类为守护线程类,并创建双向链表。运用循环创建任务线程并启动线程。executeTask()方法是往双向链表中添加任务对象并唤醒等待任务的工作任务线程。getTask()方法根据编号获得指定的任务,并移除双向链表中的双向链表中的第一个任务线程。
(4)waitTaskFinish()方法是等待任务线程执行所有的任务。在其同步块中唤醒等待任务的工作任务线程并设置标识为真。根据活动的线程数创建现场数组,根据活动的线程获得线程组中当前所有活动的工作线程,再运用循环通过join()方法等待所有工作线程结束。closeThreadPool()方法判断标识,如果标识为真,则调用waitTaskFinish()方法将等待的任务线程的所有的任务执行完毕。若设置标识为假,清空双向链表中的任务,唤醒线程池中的所有工作线程。
(5) 对于线程池的三个ThreadPool对象运用了wait和notify的方法。在getTask方法中使用wait方法来等待工作任务,等待list元素;exexcuteTask()方法中把工作任务放入list后,便调用notify方法通知线程池的三个ThreadPool对象取工作任务。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值