为了节省系统在多线程并发情况下不断的创建新和销毁线程所带来的性能浪费,就需要引入线程池。
线程池的基本功能就是线程复用。每当系统提交一个任务时,会尝试从线程池内取出空闲线程来执行它。如果没有空闲线程,这时候再创建新的线程。任务执行完毕,线程也不会立即销毁,而是加入到线程池中以便下次复用。
Java提供了多种线程池的实现,以满足不同业务的需求。为了理解它们,下面给出一个最简单的线程池的实现。
线程池主要分为两大部分,线程池和一些永不退出的线程
首先是线程池部分:
package optimistic;
import java.util.List;
import java.util.Vector;
public class ThreadPool {
//使用单例模式创建线程池
private static ThreadPool pool;
private final List<PThread> threads;
private volatile boolean isShutdown;
private int threadCount = 0;
// 在线程中调用,用来将自己加入线程池中
synchronized public void putThread(PThread t) {
if (!isShutdown) {
threads.add(t);
} else {
t.shutdown();
}
}
// 客户端用来执行自己的一项任务
synchronized public void start(Runnable task) {
if (!isShutdown) {
if (threads.size() < 1) {
new PThread(task, pool).start();
} else {
PThread p = threads.remove(0);
//设置好
p.setTarget(task);
}
}
}
//初始化一个大小为5的线程池数组
synchronized public static ThreadPool getThreadPool() {
if (pool == null) {
pool = new ThreadPool(5);
}
return pool;
}
public ThreadPool(int poolSize) {
threads = new Vector<PThread>(poolSize);
isShutdown = false;
}
//如果关闭线程池,需要将所有线程也关闭
synchronized public void shutdown() {
for(PThread p : threads)
p.shutdown();
threads.clear();
isShutdown = true;
}
public int getThreadCount(){
return threads.size();
}
}
其次,我们还需要一个永不退出的线程与之配合。
package optimistic;
public class PThread extends Thread {
private final ThreadPool pool;
private volatile boolean isShutdown;
private Runnable target;
public PThread(Runnable task, ThreadPool pool) {
this.target = task;
this.pool = pool;
isShutdown = false;
}
@Override
public void run() {
while (!isShutdown) {
if (target != null) {
target.run();
}
try {
pool.putThread(this);
// 线程执行完任务,会在wait处阻塞,直到 setTarget或者 shutdown 调用notifyAll
synchronized (this) {
wait();
}
} catch (InterruptedException e) {
}
}
}
// 每当设置任务或关闭时会唤醒run方法
synchronized public void setTarget(Runnable r) {
this.target = r;
notifyAll();
}
synchronized public void shutdown() {
isShutdown = true;
notifyAll();
}
}
完成这主要的两部分之后,我们就只需要定义一个Runnable和一个主线程就好了。
package optimistic;
public class Controller {
public static void main(String[] args) throws InterruptedException {
ThreadPool pool = ThreadPool.getThreadPool();
Runnable r = new Runnable() {
public void run() {
System.out.println(Thread.currentThread().getName());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
for (int i = 0; i < 10; i++)
pool.start(r);
Thread.sleep(1500);
System.out.println(pool.getThreadCount());
pool.shutdown();
Thread.sleep(1000);
System.out.println(pool.getThreadCount());
}
}