多线程的使用——模拟线程池的实现(2015-12-02 00:14:59)

线程池接口:

package com.dreyer.pattern.threadPool;

/**

 * @description 线程池接口

 * @author Dreyer

 * @email 
[email protected]

 * @date 2015年12月1日 下午11:03:09

 * @version 1.0

 */

public interface ThreadPool<Job extends Runnable> {

    /**

     * 执行一个Job任务,这个Job需要实现Runable接口

     * 

     * @param job

     */

    void execute(Job job);

    /**

     * 关闭线程池

     */

    void shutDown();

    /**

     * 增加工作线程者

     * 

     * @param number

     */

    void addWorkers(int number);

    /**

     * 减少工作者线程

     * 

     * @param number

     */

    void removeWorker(int number);

    /**

     * 得到正在等待执行的Job任务数量

     * 

     * @return

     */

    int getJobSize();

}


线程池接口实现类:

package com.dreyer.pattern.threadPool;

import java.util.ArrayList;

import java.util.Collections;

import java.util.LinkedList;

import java.util.List;

import java.util.concurrent.atomic.AtomicLong;

/**

 * @description 线程池ThreadPool接口的默认实现类

 * @author Dreyer

 * @email 
[email protected]

 * @date 2015年12月1日 下午11:07:40

 * @version 1.0

 */

public class DefaultThreadPool<Job extends Runnable> implements ThreadPool<Job> {

    /**

     * 线程池的最大限制数

     */

    private static final int MAX_WORKER_NUMBERS = 10;

    /**

     * 线程池的默认数量

     */

    private static final int DEFAULT_WORKER_NUMBERS = 5;

    /**

     * 线程池的最小数量

     */

    private static final int MIN_WORKER_NUMBERS = 1;

    /**

     * 工作任务列表集合

     */

    private final LinkedList<Job> jobs = new LinkedList<Job>();

    /**

     * 工作者裂变

     */

    private final List<Worker> workers = Collections

            .synchronizedList(new ArrayList<Worker>());

    /**

     * 工作者线程数量

     */

    private int workerNumber = DEFAULT_WORKER_NUMBERS;

    /**

     * 线程编号生成

     */

    private AtomicLong threadNum = new AtomicLong();

    

    /**

     * 默认构造函数初始化

     * @param number

     */

    public DefaultThreadPool() {

        initializeWorkers(DEFAULT_WORKER_NUMBERS);

    }

    

    /**

     * 构造函数指定工作者线程数量进行初始化

     * @param number

     */

    public DefaultThreadPool(int number) {

        workerNumber = number > MAX_WORKER_NUMBERS ? MAX_WORKER_NUMBERS : number < MIN_WORKER_NUMBERS ? MIN_WORKER_NUMBERS : number;

    }

    /**

     * 初始化线程工作者

     * 

     * @param number

     */

    private void initializeWorkers(int number) {

        for (int i = 0; i < number; i++) {

            Worker worker = new Worker();

            workers.add(worker);

            Thread thread = new Thread(worker,"Thread-Worker-" + threadNum.incrementAndGet());

            thread.start();

        }

    }

    @Override

    public void execute(Job job) {

        if(job != null) {

            // 添加一个工作任务,然后进行通知

            synchronized (jobs) {

                jobs.addLast(job);

                jobs.notify();

            }

        }

    }

    @Override

    public void shutDown() {

        for(Worker worker : workers) {

            worker.shutDown();

        }

    }

    @Override

    public void addWorkers(int number) {

        synchronized (jobs) {

            // 限制新增的Worker数量不能超过最大值

            if(number + this.workerNumber > MAX_WORKER_NUMBERS) {

                number = MAX_WORKER_NUMBERS - this.workerNumber;

            }

            // 按照添加的工作者数量,再进行初始化,然后增加工作者线程数量的值

            initializeWorkers(number);

            this.workerNumber += number;

        }

    }

    @Override

    public void removeWorker(int number) {

        synchronized (jobs) {

            if(number >= this.workerNumber) {

                throw new IllegalArgumentException("beyond workNumber");

            }

            // 按照给定的数量停止Worker

            int count = 0;

            while(count < number) {

                Worker worker = workers.get(count);

                if(workers.remove(worker)) {

                    worker.shutDown();

                    count ++;

                }

            }

            this.workerNumber -= count;

        }

    }

    @Override

    public int getJobSize() {

        

        return jobs.size();

    }

    /**

     * 工作者,负责消费

     * @author Dreyer

     *

     */

    class Worker implements Runnable {

        /**

         * 工作者是否工作的标识

         */

        private volatile boolean running = true;

        @SuppressWarnings("null")

        @Override

        public void run() {

            while(running) {

                Job job = null;

                synchronized (jobs) {

                    // 如果工作任务列表为空,则等待

                    while(jobs.isEmpty()) {

                        try {

                            job.wait();

                        } catch (InterruptedException e) {

                            // 感知到外部对WorkerThread的中断操作,返回

                            Thread.currentThread().interrupt();

                            return;

                        }

                    }

                    // 取出一个job

                    job = jobs.removeFirst();

                }

                if(job != null) {

                    try{

                        job.run();

                    } catch(Exception e) {

                        // 处理执行异常

                        e.printStackTrace();

                    }

                }

            }

        }

        

        /**

         * 使任务终止

         */

        public void shutDown() {

            running = false;

        }

        

    }

}

附录:packageInfo说明
对于服务端的程序,经常面对的是客户端传入的短小(执行时间短,工作内容较为单一)的任务,需要服务端快速处理并且返回结果,如果服务端每次接收到一个任务,创建一个线程,然后执行,这在原型阶段是个不错的选择,但是面对成千上万的任务提交进服务器时,如果还是采用一个任务一个线程的方式,那么将会创建数以万计的线程,这不是一个好的选择。因为这会使得操作系统频繁进行上下文切换,无故增加服务器负载,而线程的创建和消亡都是需要耗费系统资源的,也无疑浪费了系统资源。

线程池技术能够很好的解决这个问题,它预先创建了若干数量的线程,并且不能由用户直接对线程的创建进行控制,在这个前提下重复使用固定或较为固定的线程数来完成任务的执行。这样做的好处是,一方面,消除了频繁创建和消亡线程的系统资源开销,另一方面,面对过量的任务提交能够平缓的劣化。

通过代码的例子,我们可以知道,客户端可以通过execute(Job job)方法将Job提交到线程池执行,而客户端自身不用等待Job的执行完成。除了execute(Job)方法以外,线程池接口还提供了增大/减小工作者线程以及关闭线程池的方法。这里的工作者线程代表着一个重复可执行的Job的线程,而每个由客户端提交的Job都将进入到一个工作队列中等待工作者线程的处理。

从线程池的实现可以看出,当客户端调用execute(Job job)方法时,会不断的向任务列表jobs中添加Job,而每个工作者线程会不断的的从jobs上取出一个Job进行执行,当jobs为空的时候,工作者线程进入等待状态。添加一个Job后,对工作队列jobs调用其notify()方法,而不是notifyAll()方法,因为能够确定有工作者线程被唤醒,这时使用notify()会比notifyAll()方法获得更小的开销(避免将等待队列中的线程全部移动到阻塞队列中)。

可以看到,线程池的本质是使用了一个线程安全的工作队列连接工作者线程和客户端线程,客户端线程将任务放入工作队列中后便返回,而工作者线程则不断的从工作队列上取出工作并执行。当工作队列为空时,所有的工作者均等待在工作队列上,当有客户端提交了一个Job任务之后,会通知任意一个工作者线程,随着大量的任务被提交,
更多的工作者线程会被唤醒。

——以上摘自《Java并发编程的艺术》
手动的把代码敲一遍之后清晰了很多!
手动的把代码敲一遍之后清晰了很多!
手动的把代码敲一遍之后清晰了很多! 

你可能感兴趣的:(多线程、线程池实现)