Java 线程池

概要:

线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务。线程池线程都是后台线程,每个线程都使用默认的堆栈大小,以默认的优先级运行,并处于多线程单元中。本实例介绍如何运用线程池实现任务的执行。

| |目录

技术要点

    运用线程池实现任务的执行的技术要点如下:

  • 如果某个线程在托管代码中空闲,则线程池将插入另一个辅助线程来使所有处理器保持繁忙;如果所有线程池线程都始终保持繁忙,但队列中包含挂起的工作,则线程池将在一段时间后创建另一个辅助线程,但线程的数目永远不会超过最大值。超过最大值的线程可以排队,但它们要等到其他线程完成后才启动。

  • 任务放在LinkedList中,由于LinkedList不支持同步,所以在添加任务和获取任务的方法声明中必须使用synchronized关键字。

  • 关闭线程池时,通过ThreadGroup线程组获得池中所有活动线程的引用,依次调用Thread类的join()方法等待活动线程执行完毕。当所有线程运行结束时,线程池才算被关闭。

代码实现

package net.xsoftlab.baike;
import java.util.LinkedList;
class ThreadPool extends ThreadGroup {// 继承线程组实现线程池功能
	private boolean isClosed = false; // 线程池是否关闭
	private LinkedList taskQueue; // 工作任务队列
	private static int threadPool_ID = 1; // 线程池的编号
	private class TaskThread extends Thread {// 负责从工作队列中取出任务并执行的内部类
		private int id;// 任务编号
		public TaskThread(int id) {// 构造方法进行初始化
			super(ThreadPool.this, id + "");// 将线程加入到当前线程组中
			this.id = id;
		}
		public void run() {
			while (!isInterrupted()) { // isInterrupted()方法继承自Thread类,判断线程是否被中断
				Runnable task = null;
				task = getTask(id); // 取出任务
				// 如果getTask()返回null或者线程执行getTask()时被中断,则结束此线程
				if (task == null)
					return;
				try {
					task.run(); // 运行任务
				} catch (Throwable t) {
					t.printStackTrace();
				}
			}
		}
	}
	public ThreadPool(int poolSize) { // 构造方法传入线程池中的工作线程的数量
		super(threadPool_ID + ""); // 指定线程组名称
		setDaemon(true); // 继承线程组的方法用来设置是否守护线程池
		taskQueue = new LinkedList();// 创建工作任务队列
		for (int i = 0; i < poolSize; i++) {// 循环创建任务线程
			new TaskThread(i).start();// 创建并启动任务线程,根据线程池数据创建任务线程
		}
	}
	public synchronized void executeTask(Runnable task) {// 添加新任务并执行任务
		if (isClosed) {// 判断标识
			throw new IllegalStateException();// 抛出不合理状态异常
		}
		if (task != null) {
			taskQueue.add(task);// 向任务队列中加入一个任务
			notify(); // 唤醒待任务的工作任务线程
		}
	}
	private 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 synchronized void closeThreadPool() {// 关闭线程池
		if (!isClosed) {// 判断标识
			waitTaskFinish();// 等待任务线程执行完毕
			isClosed = true;// 标识为真
			taskQueue.clear();// 任务队列清空
			interrupt(); // 唤醒线程池中的所有的工作线程
		}
	}
	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 class TextThreadPool {// 操作线程池执行任务的类
	private static Runnable createTask(final int taskID) {// 创建任务方法
		return new Runnable() {
			public void run() {// 创建任务
				System.out.println("任务开始,编号为" + taskID);
				System.out.println("start task");
				System.out.println("任务结束,编号为" + taskID);
			}
		};
	}
	public static void main(String[] args) {// java程序主入口处
		ThreadPool threadPool = new ThreadPool(3); // 创建一个有个3任务线程的线程池
		try {
			Thread.sleep(600);// 休眠600毫秒,让线程池中的任务线程全部运行
		} catch (InterruptedException e) {// 捕获拦截异常
			System.out.println("线程休眠出错:" + e.getMessage());
		}
		for (int i = 0; i < 5; i++) { // 循环创建并执行任务
			threadPool.executeTask(createTask(i));
		}
		threadPool.waitTaskFinish(); // 等待所有任务执行完毕
		threadPool.closeThreadPool(); // 关闭线程池
	}
}

程序解读

  1. 内部类ThreadPool继承线程组类ThreadGroup实现线程池的功能。其私有内部类TaskThread继承Thread线程类,扩展run()方法。在run()方法中根据标识为真进行循环。根据Thread类的getTask()方法获得Runnable任务对象,调用任务对象的run()方法执行任务。

  2. ThreadPool类的构造方法传入线程池中工作线程的数量,设置该类为守护线程类,并创建双向链表。运用循环创建任务线程并启动线程。executeTask()方法是往双向链表中添加任务对象并唤醒等待任务的工作任务线程。getTask()方法根据编号获得指定的任务,并移除双向链表中的第一个任务线程。closeThreadPool()方法判断标识,如果标识为真,则调用waitTaskFinish()方法将等待的任务线程的所有的任务执行完毕。若设置标识为假,清空双向链表中的任务,唤醒线程池中的所有工作线程。

  3. waitTaskFinish()方法是等待任务线程执行所有的任务。在其同步块中唤醒等待任务的工作任务线程并设置标识为真。根据活动的线程数创建线程数组,根据活动的线程获得线程组中当前所有活动的工作线程,再运用循环通过join()方法等待所有工作线程结束。

  4. TextThreadPool类的createTask()方法根据任务编号执行指定的任务。在类的main()主方法中实例化三个ThreadPool对象,Thread类的sleep()方法使线程休眠0.6秒,运用循环执行创建的任务,调用waitTashFinish()方法等待所有的任务执行完毕再关闭线程池。


评论关闭
评论 还能输入200
评论关闭
评论 还能输入200
  • 全部评论(0)
资料加载中...
已关注 , 取消