[Java]线程池

在没有看不论什么代码之前首先想一下线程池应该有哪几部分:

  • 任务队列
  • 线程

任务队列非常好办。直接用堵塞队列就能够了:BlockingQueue<Runnable> workQueue。而线程是用来运行任务的,那么理所当然应该是不断地从任务队列中取出任务来运行,我们来看ThreadPoolExecutor中的Worker的实现:

private final class Worker implements Runnable {
	private final ReentrantLock runLock = new ReentrantLock();
	private Runnable firstTask;
	volatile long completedTasks;
	Thread thread;

	// 运行task
	private void runTask(Runnable task) {
		final ReentrantLock runLock = this.runLock;
		runLock.lock();
		try {
			// 检查线程池的状态,推断是否中断
			if (runState < STOP && Thread.interrupted() && runState >= STOP)
				thread.interrupt();
			boolean ran = false;
			beforeExecute(thread, task);// 运行任务前的操作
			try {
				task.run(); // 任务開始运行
				ran = true;
				afterExecute(task, null);// 运行任务后的操作
				++completedTasks;
			} catch (RuntimeException ex) {
				if (!ran)
					afterExecute(task, ex);// 运行任务后的操作
				throw ex;
			}
		} finally {
			runLock.unlock();
		}
	}

	// 线程启动之后開始运行
	public void run() {
		try {
			Runnable task = firstTask;
			firstTask = null;

			// 从线程池中取出Runnable然后运行
			while (task != null || (task = getTask()) != null) {
				runTask(task);
				task = null;
			}
		} finally {
			workerDone(this);
		}
	}
}

通过推断runLock是不是锁上的状态就能够推断Worker是否在运行任务了。当然getTask失败的时候,Worker的任务也就结束了,我们有时候会希望线程去等一段时间,假设这段时间里面没有任务到达线程才退出。

这个在堵塞队列中有线程的方法。在getTask能够看到,例如以下:

r = workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS);

在拿到任务的时候,假设如今线程池还非常小,那么如今不须要将任务放到堵塞队列里面去,直接创建一个线程执行就能够了。在这条路走不通的时候才会“绕弯路”来做。由于堵塞队列也是有容量限制的,那么在尝试将任务放进去的时候可能会失败。

假设让我写的话就不会尝试了,而是直接调用堵塞方法让主线程堵塞在这里,这样事实上并不好:

  • 不够灵活
  • 调用的线程被堵塞了,浪费资源,事实上它是能够用来运行任务的

假设自己要实现reject策略的话实现以下接口就能够了:

public interface RejectedExecutionHandler {
	void rejectedExecution(Runnable r, ThreadPoolExecutor executor);
}

有可能出现一种情况:插入任务之后线程池的状态改变了。那么也要保证该任务可以被处理(并不一定是任务被完毕。也可能是拒绝),那么以下来看提交任务的完整逻辑:

public void execute(Runnable command) {
	if (command == null)
		throw new NullPointerException();
	// 尝试创建线程并运行任务
	if (poolSize >= corePoolSize || !addIfUnderCorePoolSize(command)) {
		// 尝试将线程放入堵塞队列
		if (runState == RUNNING && workQueue.offer(command)) {
			if (runState != RUNNING || poolSize == 0)
				// 确保任务会被处理
				ensureQueuedTaskHandled(command);
		} else if (!addIfUnderMaximumPoolSize(command))// 假设如今能创建一个线程运行该任务的话,就不要拒绝它了。。

。
			reject(command);
	}
}

能够发如今线程池执行期间改动各种阀值都是能够起到作用的。假设在spring中想用简单的线程池的话没有必要自己写一个,直接用现成的配置一个就能够了,比方:

<bean id="taskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
	<property name="corePoolSize" value="5" />
	<property name="maxPoolSize" value="10" />
	<property name="queueCapacity" value="25" />
</bean> 

---------- ---------- ---------- ---------- END ---------- ---------- ---------- ----------

时间: 2024-10-10 22:36:07

[Java]线程池的相关文章

Java线程池应用

Executors工具类用于创建Java线程池和定时器. newFixedThreadPool:创建一个可重用固定线程数的线程池,以共享的无界队列方式来运行这些线程.在任意点,在大多数 nThreads 线程会处于处理任务的活动状态.如果在所有线程处于活动状态时提交附加任务,则在有可用线程之前,附加任务将在队列中等待.如果在关闭前的执行期间由于失败而导致任何线程终止,那么一个新线程将代替它执行后续的任务(如果需要).在某个线程被显式地关闭之前,池中的线程将一直存在. 创建一个固定大小的线程池来执

java线程池

1.new Thread的弊端 执行一个异步任务你还只是如下new Thread吗? 1 new Thread(new Runnable() { 2 3 @Override 4 public void run() { 5 // TODO Auto-generated method stub 6 } 7 }).start(); 那你就out太多了,new Thread的弊端如下: a. 每次new Thread新建对象性能差. b. 线程缺乏统一管理,可能无限制新建线程,相互之间竞争,及可能占用过

Java线程池使用说明

Java线程池使用说明 一 简介 线程的使用在java中占有极其重要的地位,在jdk1.4极其之前的jdk版本中,关于线程池的使用是极其简陋的.在jdk1.5之后这一情况有了很大的改观.Jdk1.5之后加入了java.util.concurrent包,这个包中主要介绍java中线程以及线程池的使用.为我们在开发中处理线程的问题提供了非常大的帮助. 二:线程池 线程池的作用: 线程池作用就是限制系统中执行线程的数量.     根 据系统的环境情况,可以自动或手动设置线程数量,达到运行的最佳效果:少

Java 线程池的原理与实现

最近在学习线程池.内存控制等关于提高程序运行性能方面的编程技术,在网上看到有一哥们写得不错,故和大家一起分享. [分享]Java 线程池的原理与实现 这几天主要是狂看源程序,在弥补了一些以前知识空白的同时,也学会了不少新的知识(比如 NIO),或者称为新技术吧.线程池就是其中之一,一提到线程,我们会想到以前<操作系统>的生产者与消费者,信号量,同步控制等等.一提到池,我们会想到数据库连接池,但是线程池又如何呢? 建议:在阅读本文前,先理一理同步的知识,特别是syncronized同步关键字的用

Java 线程池学习

Reference: <创建Java线程池>[1],<Java线程:新特征-线程池>[2], <Java线程池学习>[3],<线程池ThreadPoolExecutor使用简介>[4],<Java5中的线程池实例讲解>[5],<ThreadPoolExecutor使用和思考>[6] [1]中博主自己通过ThreadGroup实现一个线程池(挺方便理解的),使用的是jdk1.4版本,Jdk1.5版本以上提供了现成的线程池. [2]中介绍

JAVA线程池的分析和使用

http://www.infoq.com/cn/articles/java-threadPool/ 1. 引言 合理利用线程池能够带来三个好处.第一:降低资源消耗.通过重复利用已创建的线程降低线程创建和销毁造成的消耗.第二:提高响应速度.当任务到达时,任务可以不需要等到线程创建就能立即执行.第三:提高线程的可管理性.线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控.但是要做到合理的利用线程池,必须对其原理了如指掌. 2. 线程池

java线程池分析和应用

比较 在前面的一些文章里,我们已经讨论了手工创建和管理线程.在实际应用中我们有的时候也会经常听到线程池这个概念.在这里,我们可以先针对手工创建管理线程和通过线程池来管理做一个比较.通常,我们如果手工创建线程,需要定义线程执行对象,它实现的接口.然后再创建一个线程对象,将我们定义好的对象执行部分装载到线程中.对于线程的创建.结束和结果的获取都需要我们来考虑.如果我们需要用到很多的线程时,对线程的管理就会变得比较困难.我们手工定义线程的方式在时间和空间效率方面会存在着一些不足.比如说我们定义好的线程

Java线程池:ExecutorService,Executors

简单的Java线程池可以从Executors.newFixedThreadPool( int n)获得.此方法返回一个线程容量为n的线程池.然后ExecutorService的execute执行之. 现给出一个示例. package zhangphil.executorservice; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class ZhangPhil

JAVA线程池ThreadPoolExecutor与阻塞队列BlockingQueue .

从Java5开始,Java提供了自己的线程池.每次只执行指定数量的线程,java.util.concurrent.ThreadPoolExecutor 就是这样的线程池.以下是我的学习过程. 首先是构造函数签名如下: [java] view plain copy print ? public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<

Java线程池使用和分析(二) - execute()原理

相关文章目录: Java线程池使用和分析(一) Java线程池使用和分析(二) - execute()原理 execute()是 java.util.concurrent.Executor接口中唯一的方法,JDK注释中的描述是“在未来的某一时刻执行命令command”,即向线程池中提交任务,在未来某个时刻执行,提交的任务必须实现Runnable接口,该提交方式不能获取返回值.下面是对execute()方法内部原理的分析,分析前先简单介绍线程池有哪些状态,在一系列执行过程中涉及线程池状态相关的判断