简单模拟线程池

前言:
引入线程池的原因:
线程的创建和销毁是需要消耗系统资源的(包括时间)。
如果能够在大量线程的开辟和销毁的情况下,不是真正地创建或者销毁线程,而是通过“池子”,预备线程,供用户使用,这样就可以节省大量时间。

两种方式:
1.先创建一些“空线程”,等待用户任务;
2.在用户提出任务执行需求时,临时创建线程,但是这些线程在执行完任务后,不是真的结束和销毁,而是存储到“线程池”中,等待下一次调用。

这里使用第二种方式模拟线程池
Java中创建一个线程池所需要的参数:

corePoolSize:最少的活跃数量
maximumPoolSize:最大线程池数量
keepAliveTime:当线程数量处于上面两个之间时,查看空闲的线程所空闲的时间,大于keepAliveTime就结束掉当前线程
TimeUnit:是keepAliveTime的单位,workQueue:存放任务的队列的类型,这里采用链表方式的阻塞队列。

封装用户任务的类Task(实际是线程):
这个类将用户任务线程作为成员,且该类也实现Runnable接口,使得在该类中的run()方法中执行用户任务线程的run()方法。

	public static final boolean BUSY = true;
    public static final boolean FREE = falseprivate volatile Runnable job;//需要执行的任务的线程
    private volatile boolean status;//线程是否可用的标志
    private volatile boolean goon;
    private volatile Object lock;//每一个Task有一个对象锁,为了解决线程的阻塞和唤醒
    private final IThreadPoolTask threadPoolTask;

    Task(Runnable job, IThreadPoolTask threadPoolTask) {
        this.lock = new Object();
        this.threadPoolTask = threadPoolTask;//不能再次更改,即每一个任务都有自己单独的闲池子和忙池子。
        this.job = job;
        this.status = BUSY;
        this.goon = true;

        new Thread(this).start();//每创建一个Task就会创建一个新线程
    }
void setJob(Runnable job) {
        //这里并不需要判断thread是否被占用,因为,我们每次取线程是在闲线程池中获取
        synchronized (this.lock) {
            this.job = job;
            this.status = BUSY;
            if (this.goon) {
                this.threadPoolTask.moveToBusyPool(this);//设置任务时把线程放到忙线程池中
            }
            synchronized (this.lock) {
                this.lock.notify();
            }
        }
    }
    @Override
    public void run() {
        while (this.goon) {
            if (this.status == BUSY) { //表明该线程有任务
                this.job.run();//这里run()为普通方法,调用完后,线程进入阻塞状态

                    if (this.goon == false) {
                        continue;
                        //这是为了结束线程做的准备
                    }

                    this.status = FREE;
                    this.threadPoolTask.moveToFreePool(this);//并且需要将线程从忙线程池中迁移到闲线程池中
                    try {
                        synchronized (this.lock) {
                            this.lock.wait();//线程处于阻塞态除非唤醒否则无法关闭线程
                        }
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }

Task类实际是线程,在任务执行完毕后,线程进入阻塞态,等待下一次设置任务时再次唤醒它。

管理任务的线程池:
我们首先需要两个两个池子:

this.freePool = new ArrayList();//把闲池子当做队列,从末尾插入,从头取出
this.busyPool = new LinkedList();//忙池子因为线程不是排队结束的,他的结束时很随机的,所以用LinkedLit。

public void setJob(Runnable job) {
        Task task = null;
        if (this.freePool.isEmpty()) {
            task = new Task(job, this);
            synchronized (this.lock) {
                this.busyPool.add(task);
            }
        } else {
            synchronized (this.lock) {
                task = this.freePool.get(0);
            }
            task.setJob(job);
        }
    }
    //结束线程池中的所有线程
    //为了防止两个线程池互相移动出现问题,首先把两个池子中的线程放到一起,然后遍历关闭
    public void terminate() {
        List<Task> allTask = new ArrayList<>();
        synchronized (this.lock) {
            for (Task task : this.freePool) {
                if (!allTask.contains(task)) {
                    allTask.add(task);
                }
            }
            for (Task task : this.freePool) {
                if (!allTask.contains(task)) {
                    allTask.add(task);
                }
            }
        }
        for (Task task : allTask) {
            task.terminate();
            if (task.getStatus() == false) {
                synchronized (task.getLock()) {
                    task.getLock().notify();
                }
            }
        }
    }

该简单线程池的流程图:
简单模拟线程池_第1张图片
补充:
这里只是简单实现了线程池的大致过程,并没有运用到开头我们所说的JDK自带的线程池中的四个成员。

你可能感兴趣的:(线程池,java)