目录
原理
自定义线程池的原理很简单,一共三个,一个是线程同步问题,一个是线程通信,另一个我认为最核心的原理没有官方的名字,我把它叫做线程与run()的分离,有关线程同步的介绍请看这里,有关线程通信的介绍及示例代码请看这里。
关于线程与run()的分离,回想多线程的三种实现方法:继承Thread类,实现Runable接口,或者是匿名类(包括Thread匿名类和Runable匿名类),把我们想执行的代码告诉线程的方法,都是重写run方法。看下面这段代码
Runnable task=new Runnable() {
@Override
public void run() {
....
};
Thread t=new Thread(task).start();
这样的代码相信很多人都写过,并没有多高深的地方,但是我在理解线程池的时候想到了这段代码,这里体现了一个思想:线程是线程,run方法是run方法。它俩是可以分开的。
如果我们把Runable的一个实例叫做一个任务,那么我们也可以说,线程和任务是可以分开的。
线程池的核心思想就是线程与任务的分离,先启动几个线程进入wait状态,等有任务的时候通知一个线程来领任务,领到任务的线程执行任务的run方法,执行完再进入wait状态。这样就是可以重复利用线程的线程池了。
为了好理解,我们把一个Runable的实例作为一个任务,java自带的线程池ThreadPoolExecutor也是用Runable的实例作为任务的,但实际是在我们自定义的线程池里,我们可以自己定义任务对象和任务方法(可以不用叫run())。为了方便,下面的实例代码都还是用的Runnable。
示例代码
自定义线程池:
import java.util.ArrayList;
import java.util.List;
public class MyThreadPool {
int size;
List<Runnable> tasks=new ArrayList<Runnable>();
public MyThreadPool(int size) {
this.size=size;
for(int i=0;i<size;i++)
new ConsumeThread("线程"+i).start();
}
public void addTask(Runnable task)
{
synchronized(tasks)
{
tasks.add(task);
tasks.notify();
}
}
private class ConsumeThread extends Thread{
public ConsumeThread(String name) {
super(name);
}
@Override
public void run() {
while(true)
{
Runnable task = null;
//竞争tasks
synchronized(tasks)
{
System.out.println(this.getName()+"占有tasks");
try {
//如果tasks为空,则进入休眠状态
if(tasks.isEmpty())
{
System.out.println(this.getName()+"进入休眠状态");
tasks.wait();
//被唤醒后跳出这轮循环重写检测tasks是否为空
continue;
}
//tasks不为空,取出一个任务开始执行
task=tasks.remove(0);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//取出一个任务就释放tasks,否则任务在synchronized(tasks)内执行的话,任务执行期间,其他任务就不能被其他线程取出执行。
if(task!=null)
task.run();
//任务执行结束,继续竞争tasks执行任务直到任务池为空
}
}
}
}
测试类:
public class MyThreadPoolTest {
public static void main(String[] args) {
MyThreadPool tp=new MyThreadPool(5 );
for(int i=0;i<100;i++)
{
Runnable task=new Runnable() {
@Override
public void run() {
try {
//假设这是执行一个任务所用时间
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("\t\t\t任务执行完毕");
}
};
tp.addTask(task);
}
}
}