线程池的原理及实现

一、线程池简介

多线程技术主要解决处理器单元内多个线程执行的问题,它可以显著减少处理器单元的闲置时间,增加处理器单元的吞吐能力。

假设一个服务器完成一项任务所需时间为:T1 创建线程时间,T2 在线程中执行任务的时间,T3 销毁线程时间。

如果:T1 + T3 远大于 T2,则可以采用线程池,以提高服务器性能。

一个线程池包括以下四个基本组成部分:

  1. 线程池管理器(ThreadPool):用于创建并管理线程池,包括 创建线程池,销毁线程池,添加新任务;
  2. 工作线程(PoolWorker):线程池中线程,在没有任务时处于等待状态,可以循环的执行任务;
  3. 任务接口(Task):每个任务必须实现的接口,以供工作线程调度任务的执行,它主要规定了任务的入口,任务执行完后的收尾工作,任务的执行状态等;
  4. 任务队列(taskQueue):用于存放没有处理的任务。提供一种缓冲机制。

线程池技术正是关注如何缩短或调整T1,T3时间的技术,从而提高服务器程序性能的。它把T1,T3分别安排在服务器程序的启动和结束的时间段或者一些空闲的时间段,这样在服务器程序处理客户请求时,不会有T1,T3的开销了。

线程池不仅调整T1,T3产生的时间段,而且它还显著减少了创建线程的数目,看一个例子:

假设一个服务器一天要处理50000个请求,并且每个请求需要一个单独的线程完成。在线程池中,线程数一般是固定的,所以产生线程总数不会超过线程池中线程的数目,而如果服务器不利用线程池来处理这些请求则线程总数为50000。一般线程池大小是远小于50000。所以利用线程池的服务器程序不会为了创建50000而在处理请求时浪费时间,从而提高效率。

下面代码实现中并没有实现任务接口,而是把Runnable对象加入到线程池管理器(ThreadPool),然后剩下的事情就由线程池管理器(ThreadPool)来完成了。

package wb;

import java.util.LinkedList;
import java.util.List;

/** 
 * 线程池类,线程管理器:创建线程,执行任务,销毁线程,获取线程基本信息 
 */ 
public final class ThreadPool {
    // 线程池中默认线程的个数为5 
    private static int workNum = 5;
    // 任务队列,作为一个缓冲,List线程不安全  
    private List<Runnable> taskQueue = new LinkedList<Runnable>();  
    // 未处理的任务  
    private static volatile int finishedNum = 0;  
    // 工作线程  
    private WorkThread[] workThrads;  
    private static ThreadPool threadPool; 

    // 创建具有默认线程个数的线程池
    private ThreadPool() {
        this(5);
    }

    // 创建线程池,worker_num为线程池中工作线程的个数
    private ThreadPool(int workNum) {
        ThreadPool.workNum = workNum;
        workThrads = new WorkThread[workNum];
        for (int i = 0; i < workNum; i++) {
            workThrads[i] = new WorkThread();
            workThrads[i].start();
        }
    }

    // 单态模式,获得一个默认线程个数的线程池
    public static ThreadPool getThreadPool() {
        return getThreadPool(threadPool.workNum);
    }

    // 单态模式,获得一个指定线程个数的线程池,worker_num(>0)为线程池中工作线程的个数  
    // worker_num<=0创建默认的工作线程个数  
    public static ThreadPool getThreadPool(int workNum2) {
        if (workNum2 <= 0) {
            workNum2 = threadPool.workNum;
        }
        if (threadPool == null) {
            threadPool = new ThreadPool(workNum2);
        }
        return threadPool;
    }

    // 执行任务,其实只是把任务加入任务队列,什么时候执行有线程池管理器决定
    public void execute(Runnable task) {
        synchronized (taskQueue) {
            taskQueue.add(task);
            taskQueue.notify();
        }
    }

    // 批量执行任务,其实只是把任务加入任务队列,什么时候执行有线程池管理器决定
    public void execute(Runnable[] tasks) {
        synchronized (taskQueue) {
            for (Runnable task : tasks) {
                taskQueue.add(task);
                taskQueue.notify();
            }
        }
    }

    // 销毁线程池,该方法保证在所有任务都完成的情况下才销毁所有线程,否则等待任务完成才销毁
    public void destory() {
        while (!taskQueue.isEmpty()) {// 如果还有任务没执行完成,就先睡会吧
            try {
                Thread.sleep(10);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        // 工作线程停止工作,且置为null  
        for (int i = 0; i < workNum; i++) {
            workThrads[i].stopWork();
            workThrads[i] = null;
        }
        threadPool = null;
        taskQueue.clear();
    }

    // 返回工作线程的个数  
    public int getWorkThreadNumber() {  
        return workNum;  
    }  

    // 返回已完成任务的个数,这里的已完成是只出了任务队列的任务个数,可能该任务并没有实际执行完成  
    public int getFinishedTasknumber() {  
        return finishedNum;  
    } 

    // 返回任务队列的长度,即还没处理的任务个数  
    public int getWaitTasknumber() {  
        return taskQueue.size();  
    }  

    // 覆盖toString方法,返回线程池信息:工作线程个数和已完成任务个数  
    @Override  
    public String toString() {  
        return "线程总数:" + workNum+ ",已完成的线程总数:" + finishedNum + ",等待的线程总数" + getWaitTasknumber();  
    } 

    private class WorkThread extends Thread {
        // 该工作线程是否有效,用于结束该工作线程 
        private boolean isRunning = true;
        /* 
         * 关键所在啊,如果任务队列不空,则取出任务执行,若任务队列空,则等待 
         */
        @Override
        public void run() {
            Runnable run = null;
            while (isRunning) {// 注意,若线程无效则自然结束run方法,该线程就没用了 
                synchronized (taskQueue) {
                    while (isRunning && taskQueue.isEmpty()) {// 队列为空
                        try {
                            taskQueue.wait(20);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                    if (!taskQueue.isEmpty()) {
                        run = taskQueue.remove(0);// 取出任务
                    }
                }
                if (run != null) {
                    run.run();// 执行任务
                }
                finishedNum++;
                run = null;
            }
        } 
        // 停止工作,让该线程自然执行完run方法,自然结束 
        public void stopWork() {
            isRunning = false;
        }
    }
}

测试:

package wb;

/**
 * 测试线程池
 */
public class TestThreadPool {
    public static void main(String[] args) {
        // 创建3个线程的线程池
        ThreadPool pool = ThreadPool.getThreadPool(3);
        pool.execute(new Runnable[]{new Task(), new Task(), new Task()});
        pool.execute(new Runnable[]{new Task(), new Task(), new Task()});
        System.out.println(pool);
        pool.destory();
        System.out.println(pool);
    }
    private static class Task implements Runnable {
        private static volatile int i = 1;
        @Override
        public void run() {
            System.out.println("任务" + (i++) + "完成");
        }
    }
}

二、java类库中提供的线程池简介

这里写图片描述
这里写图片描述

三、Spring线程池ThreadPoolTaskExecutor

线程池配置:

<bean id="taskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">  
        <!-- 核心线程数 -->  
        <property name="corePoolSize" value="5" />  
        <!-- 最大线程数 -->  
        <property name="maxPoolSize" value="10" />  
        <!-- 队列最大长度 >=mainExecutor.maxSize -->  
        <property name="queueCapacity" value="25" />  
        <!-- 线程池维护线程所允许的空闲时间 -->  
        <property name="keepAliveSeconds" value="3000" />  
        <!-- 线程池对拒绝任务(无线程可用)的处理策略 ThreadPoolExecutor.CallerRunsPolicy策略 ,调用者的线程会执行该任务,如果执行器已关闭,则丢弃. -->  
        <property name="rejectedExecutionHandler">  
            <bean class="java.util.concurrent.ThreadPoolExecutor$CallerRunsPolicy" />  
        </property>  
    </bean>

猜你喜欢

转载自blog.csdn.net/zajiayouzai/article/details/80194781