About thread pool, you do not know those things

This article is reproduced in: https://www.cnblogs.com/hafiz/p/7589352.html#4010404

 

One, background

  In a recent study thread-related knowledge, and ultimately learn logical thread pool, beginning in the absence of in-depth learning, feeling the thread pool is very mysterious thing, and think of how to achieve a completely own thread pool, and then also to ensure it availability, and I have been pondering, pondering just few week is also a variety of online information search, and finally understand the principle of the thread pool, but also his own handwriting a thread pool, to deepen the impression, then this article we'll chat about thread pool of knowledge, hope that more ape friends can see from this there is a clear and intuitive understanding of the thread pool.

Second, the concept resolve

1. What is the thread pool

  The basic idea of ​​the thread pool is an object pooling, when the program starts to open up a piece of memory space, which kept many (not death) thread pool thread executes scheduling is handled by the pool manager. When threaded tasks, from taking a bath, after the completion of the implementation of the thread pool objects together, to avoid repeated to create a thread object brings performance overhead, saving system resources.

2. Use the thread pool Benefits

  Rational use of thread pool threads have been created can be reused, so that you can reduce the time and resources spent on the creation of threads and destroying threads. In addition, the thread pool can dynamically adjust the number of worker threads to balance resource consumption and efficiency in some cases. At the same time the thread pool also provides a method of work-related thread pool unified management. This is equivalent to our first created, it can be used repeatedly, saving a lot of system resources, frequent creating and destroying threads need.

3. The main components of the thread pool

A thread pool consists of four basic components:
(1), the thread pool manager (ThreadPool): used to create and manage the thread pool, including creating a thread pool, the destruction of the thread pool, add new tasks;
(2), the worker thread (WorkThread): thread pool, when there is no task in a wait state, you can perform tasks cycle;
(3), the task Interface (task): each task must implement, for the implementation of thread scheduling tasks, it mainly provides entrance task, finishing the job is finished, the execution status of the task and the like;
(4), task queue (taskQueue): for storing task is not processed. Provide a buffering mechanism.

In 4.JDK common thread pool classes UML class diagram

Third, realize handwriting

We know that the thread pool of principle and major components after, let us manually implement its own thread pool, to deepen understanding and in-depth study.

1. Thread pool interface class

package com.hafiz.proxy.threadPool;

import java.util.List;

/**
 * Desc:线程池接口类
 * Created by hafiz.zhang on 2017/9/19.
 */
public interface ThreadPool {

    // 执行单个线程任务
    void execute(Runnable task);

    // 执行多个任务
    void execute(Runnable[] tasks);

    // 执行多个任务
    void execute(List<Runnable> tasks);

    // 返回已经执行的任务个数
    int getExecuteTaskNumber();

    // 返回等待被处理的任务个数,队列的长度
    int getWaitTaskNumber();

    // 返回正在工作的线程的个数
    int getWorkThreadNumber();

    // 关闭线程池
    void destroy();
}

2.线程池实现类ThreadPoolManager.java

package com.hafiz.proxy.threadPool;

import java.util.Arrays;
import java.util.List;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicLong;

/**
 * Desc:线程池实现类
 * Created by hafiz.zhang on 2017/9/19.
 */
public class ThreadPoolManager implements ThreadPool {

    // 线程池中默认线程的个数为5
    private static Integer workerNum = 5;

    // 工作线程数组
    WorkThread[] workThreads;

    // 正在执行的线程任务数量
    private static volatile Integer executeTaskNumber = 0;

    // 任务队列, 作为一个缓冲
    private Queue<Runnable> taskQueue = new ConcurrentLinkedQueue<>();

    // 单例模式
    private static ThreadPoolManager threadPool;

    private AtomicLong threadNum = new AtomicLong();

    private ThreadPoolManager() {
        this(ThreadPoolManager.workerNum);
    }

    private ThreadPoolManager(int workerNum) {
        if (workerNum > 0) {
            ThreadPoolManager.workerNum = workerNum;
        }
        workThreads = new WorkThread[ThreadPoolManager.workerNum];
        for (int i = 0; i < ThreadPoolManager.workerNum; i++) {
            workThreads[i] = new WorkThread();
            Thread thread = new Thread(workThreads[i], "ThreadPool-worker-" + threadNum.incrementAndGet());
            thread.start();
            System.out.println("初始化线程总数:" + (i+1) + ",当前线程名称是:ThreadPool-worker-" + threadNum);
        }
    }

    public static ThreadPool getThreadPool() {
        return getThreadPool(workerNum);
    }

    public static ThreadPool getThreadPool(int workerNum) {
        if (workerNum > 0) {
            ThreadPoolManager.workerNum = workerNum;
        }
        if (threadPool == null) {
            threadPool = new ThreadPoolManager(ThreadPoolManager.workerNum);
        }
        return threadPool;
    }


    @Override
    public void execute(Runnable task) {
        synchronized (taskQueue) {
            taskQueue.add(task);
            taskQueue.notifyAll();
        }
    }

    @Override
    public void execute(Runnable[] tasks) {
        execute(Arrays.asList(tasks));
    }

    @Override
    public void execute(List<Runnable> tasks) {
        synchronized (taskQueue) {
            for (Runnable task : tasks) {
                 taskQueue.add(task);
            }
            taskQueue.notifyAll();
        }
    }

    @Override
    public String toString() {
        return "ThreadPoolManager{" +
                "当前的工作线程数量=" + getWorkThreadNumber() +
                ", 已完成的任务数=" + getExecuteTaskNumber() +
                ", 等待任务数=" + getWaitTaskNumber() +
                '}';
    }

    @Override
    public int getExecuteTaskNumber() {
        return executeTaskNumber;
    }

    @Override
    public int getWaitTaskNumber() {
        return taskQueue.size();
    }

    @Override
    public int getWorkThreadNumber() {
        return workerNum;
    }

    @Override
    public void destroy() {
        while (!taskQueue.isEmpty()) {
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        for (int i = 0; i < workThreads.length; i++) {
            workThreads[i].shutdown();
            workThreads[i] = null;
        }
        threadPool = null;
        taskQueue.clear();
    }

    private class WorkThread implements Runnable {
        // 线程是否可用
        private boolean isRunning = true;

        @Override
        public void run() {
            Runnable r = null;
            while (isRunning) {
                // 队列同步机制,加锁
                synchronized (taskQueue) {
                    while (isRunning && taskQueue.isEmpty()) {
                        try {
                            taskQueue.wait(20);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    if (!taskQueue.isEmpty()) {
                        r = taskQueue.poll();
                    }
                }
                if (r != null) {
                    r.run();
                }
                executeTaskNumber++ ;
                r = null;
            }
        }

        public void shutdown() {
            isRunning = false;
        }
    }
}

其中该类中包含内部类WorkThread,它用来包装真正的线程类,给每一个线程一个是否可用的标志,该线程工作室同步的从taskQueue中取出要执行的任务进行调用run方法来执行任务。

这个类中的getThreadPool方法中我们还使用到了懒汉式来实现单例,单例模式也是Java常用设计模式之一。

注意该类中的destroy方法的实现:我们是一直等到队列中的所有的任务执行完毕,才真正的销毁线程池,销毁的过程中不要忘记将每一个线程对象置为null,并且清空任务队列,这样更利于java的垃圾回收。

3.自定义任务类Task.java

package com.hafiz.proxy.threadPool;

/**
 * Desc:自定义任务类
 * Created by hafiz.zhang on 2017/9/21.
 */
public class Task implements Runnable {

    private static volatile Integer i = 1;

    @Override
    public void run() {
        // 执行任务
        synchronized (i) {
            System.out.println("当前处理的线程是:" + Thread.currentThread().getName() + ",执行任务:" + (i++) + "完成");
        }
    }
}

4.线程池测试类

package com.hafiz.proxy.threadPool;

import java.util.ArrayList;
import java.util.List;

/**
 * Desc:线程池测试类
 * Created by hafiz.zhang on 2017/9/20.
 */
public class ThreadPoolTest {
    public static void main(String[] args) {
        ThreadPool t = ThreadPoolManager.getThreadPool(6);
        List<Runnable> tasks = new ArrayList<>();
        for (int i = 0; i < 100; i++) {
            tasks.add(new Task());
        }
        System.out.println(t);
        t.execute(tasks);
        // 所有的线程执行完成才destroy
        t.destroy();
        System.out.println(t);
    }
}

5.测试结果:(为了篇幅,只创建10个任务运行)

四、总结

  通过本文,我们弄明白线程池到底是怎么工作,学习知识的过程中,我们就是要知其然知其所以然。这样我们才能更好地驾驭它,才能更好地去理解和使用,也能更好地帮助我们触类旁通,后面有机会我们接着来说数据库连接池的原理及手写实现。

Guess you like

Origin www.cnblogs.com/JonaLin/p/11090552.html