因为创建线程是一个非常消耗资源的情况,线程也是一个重量级的对象,避免频繁的创建和销毁
为了高效的利用线程,出现了线程池这种技术
线程池和一般的资源池不一样,资源池只需要用accqure()获取资源,使用完成利用release()释放资源,Java对于线程池可没这样的提供方法
线程池在本质上来说,采用了生产者-消费者模式
线程的使用方式生产者,生产任务,线程池就是消费者,消费任务
//简化的线程池,仅用来说明工作原理
class MyThreadPool{
//利用阻塞队列实现生产者-消费者模式
BlockingQueue<Runnable> workQueue;
//保存内部工作线程
List<WorkerThread> threads
= new ArrayList<>();
// 构造方法
MyThreadPool(int poolSize,
BlockingQueue<Runnable> workQueue){
this.workQueue = workQueue;
// 创建工作线程
for(int idx=0; idx<poolSize; idx++){
WorkerThread work = new WorkerThread();
work.start();
threads.add(work);
}
}
// 提交任务
void execute(Runnable command){
workQueue.put(command);
}
// 利用多个工作线程负责消费任务,并执行任务
class WorkerThread extends Thread{
public void run() {
//循环取任务并执行
while(true){ ①
Runnable task = workQueue.take();
task.run();
}
}
}
}
/** 下面是使用示例 **/
// 创建有界阻塞队列
BlockingQueue<Runnable> workQueue =
new LinkedBlockingQueue<>(2);
// 创建线程池
MyThreadPool pool = new MyThreadPool(
10, workQueue);
// 提交任务
pool.execute(()->{
System.out.println(“hello”);
});
在整个线程池的内部,维护了一个工作队列,在其中保存了内部的工作线程
然后创建一个集合保存,所有的工作线程,在实际使用过程中,就是提交任务就是保存到队列中
在工作线程之中,就是不断的从队列中拉取任务并且执行
在java中,提供的线程池其实现可以为ThreadPoolExecutor,通过其可以生成需要的指定线程池,其构造函数为
ThreadPoolExecutor(
int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
上述的参数分别为
corePoolSize为核心线程数,为必须保留的线程数
maximumPoolSize 为最大线程数,为最大的可以用的线程数
keepAliveTime 为留存时间,即为一个线程空闲之后可以存活多久
workQueue 工作队列
threadFactory 生产线程的工厂类
handler:可以指定的拒绝策略,提供的拒绝策略有四种
CallerRunsPolicy:提交任务的线程自己去执行
AbortPolicy :直接throws RejectedExectionException
DiscardPolicy 直接丢弃任务
DiscardOldestPolicy 丢弃最老的任务,把新任务加入到队列
后续也支持了allowCoreThreadTimeOut(boolean Value)的设置,也就是corePoolSize中的线程,在超过时间空闲后也撤走
对于java自带的工具类Executors来说,生成的线程池不推荐使用,大多数都是无界的工作队列或者线程池,容易出现OOM的情况