Java线程池的核⼼思想解析
下⾯讲述java内置线程池的核⼼思想,并给出⼀个简单的程序模拟这个思想。
创建线程池的⽬的
线程的创建和销毁代价是昂贵的。
耗费资源:线程栈是在java堆外的,默认⼀个线程栈为1M空间,如果线程创建过多,内存空间会马上被消耗完。
操作系统要做的事:给它分配内存、列⼊调度。
如果是RMI机制下服务器和客户端之间的短连接。那么对于客户端的⼀个请求,服务器都会创建⼀个线程来响应这个请求,处理完这个请求就马上销毁线程。这样就会⾮常频繁的创建和销毁线程,是耗时,耗资源的。
因此,就有了线程池的这个解决⽅案:
先创建⼀定数量的线程,需要线程的时候,从这个线程池中拿出来直接⽤,⽤完了这个之后,再把这个线程放回到线程池中。⽽不是直接关闭这个线程。
线程池思想的基本实现
⾸先讲线程池中的单个线程。
我们需要让这个线程⼀直处于运⾏状态,但并没有具体处理事务,只是在不停的循环。当我们有需要的时候,要让这个线程切换⼯作内容,执⾏我们需要的代码。
所以怎么让正在运⾏的线程,切换不同⼯作内容呢?
1. 给这个线程⼀个ITasker接⼝成员,是⼀个后期⾃⼰实现的任务类。
2. 当我们没有从外部setTasker即tasker = null时,run⽅法是不会执⾏真正内容的。
3. 当setTasker之后,run⽅法就会真正执⾏这个任务类中的⽅法。
4. 执⾏完这个任务类的⽅法后,⼜让这个tasker成员等于null。还是让这个run⽅法⼀直跑着,不关闭这个线程。
public class Worker implements Runnable{
private volatile ITasker tasker;
private volatile boolean goon;
private final ThreadPool threadPool;
Worker(ThreadPool threadPool){
goon =true;
this.threadPool = threadPool;
}
void start(){
new Thread(this).start();
goon =true;
}
void stop(){
goon =false;
}
ITasker getTasker(){
return tasker;
}
void setTasker(ITasker tasker){
this.tasker = tasker;
}
@Override
public void run(){
while(goon){
if(tasker != null){
tasker.beforeTask();
try{
tasker.task();
java线程池创建的四种}catch(Throwable e){
e.printStackTrace();
}
tasker.afterTask();
tasker = null;
}
}
}
}
下⾯就是真正持有线程池的类,就是对多个Worker 类形成的池⼦的管理类。
⾸先通过线程的状态,把线程分为俩类,⼀个是空闲的线程freePool,⼀个是正在执⾏任务类代码的线程busyPool。
1. 先给空闲的线程池创建拥有基本数量的线程。
2. 当外部需要线程来跑代码时,只要调⽤NewThread()⽅法,并且传⼊这个任务类。
3. 线程池⾃动的从freePool池中到⼀个线程来执⾏这个任务类,并且把这个线程放⼊到busyPool池中。
4. ⽽当这个线程执⾏完毕后,由线程内部调⽤removeToFree()⽅法,把本线程再调回freePool中。
public class ThreadPool {
private volatile Queue<Worker> freePool;
private volatile List<Worker> busyPool;
public ThreadPool(){
busyPool =new LinkedList<Worker>();
freePool =new ConcurrentLinkedQueue<Worker>();
creatThread(5);
}
private void creatThread(int num){
for(int i =0; i < num;i++){
Worker worker =new Worker(this);
freePool.offer(worker);
}
}
public void NewThread(ITasker tasker){
if(freePool.isEmpty()){
creatThread(3);
}
Worker worker = freePool.poll();
worker.setTasker(tasker);
worker.start();
busyPool.add(worker);
}
public boolean stop(){
Worker worker;
if(busyPool.isEmpty()){
while((worker = freePool.poll())!= null){
worker.stop();
}
return true;
}
return false;
}
void removeToFree(Worker worker){
if(freePool.size()>20){
worker.stop();
return;
}
freePool.offer(worker);
}
}
通过⾃⼰模拟,初步实现了线程池的核⼼功能,但是,需要考虑如下问题:
1、应该限定“核⼼线程”数量;
所谓“核⼼线程”是⼀直处在待执⾏状态的线程;就是freePool池中最⼤的数量。
2、当核⼼线程数量达到极值,后⾯产⽣的线程不再进⼊空线程池;
3、还要控制最⼤并⾏线程数量,即busyPool中最⼤的数量。
若最⼤并⾏线程数量达到极值,则,对于⽤户产⽣的新的线程需求,不再⽴刻满⾜,⽽是等待若⼲时间,再从空线程池中获取可⽤线程。
4、对于线程池的结束,应该考虑到正在执⾏中的线程的“强制结束”,或者,“等待结束”这两种处理⽅式。
强制结束:关停所有线程,包括正在运⾏的西城。
等待结束:等待运⾏线程执⾏完对应代码,再关闭所有的线程。
使⽤内置的线程池
public class Demo {
public static void main(String[] args){
ThreadPoolExecutor threadPool =new ThreadPoolExecutor(
10
,120
,5000
, TimeUnit.MILLISECONDS
,new LinkedBlockingQueue<Runnable>());
public void run(){
//执⾏任务
}
});
}
}
我⼀开始认为实现了Runnable之后,那传⼊的类本⾝就是线程,难道线程池⾥⾯还是线程来启动线程吗?
其实不是,这个类虽然实现了Runnable接⼝,但是并不是⼀个线程,并没有在类内部new Thread (this).start();
实现Runnable接⼝之后,必然要重写run⽅法。所以线程池内部就可以通过这个统⼀的run⽅法来完成需要执⾏的任务,可以说是做到了统⼀的⽬的。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论