高并发编程-自定义简易的线程池(1),体会原理

简介: 高并发编程-自定义简易的线程池(1),体会原理

20191031000734676.png

概述


我们工作中,并发编程必然离不开jdk提供的j.u.c中的线程池 ,假设让我们自己去设计一个线程池,该从哪几个方面来着手考虑呢?


首先: 既然是线程池 , 那必然 有个初始化的线程数量 和 最大数量 ----> 两个属性 : init 和 max


其次:当线程池中的线程达到了 init 数量,但还没到max 数量的时候,将任务放入任务队列中,而不是直接开辟新的线程,是不是一种更好的设计? 所以 引入 任务队列,存放任务


最后:当线程池中的线程 把 任务队列也塞满了,也达到了Max的值,新的线程过来,我们改如何处理呢? 是不是指定拒绝策略更合适呢? 比如 直接拒绝,抛出异常,放入临时队列等等。所以 拒绝策略也是需要的


总结一下


  1. init (coreSize) / max , 线程池初始化大小和最大线程数
  2. 任务队列
  3. 拒绝策略
  4. 。。。


示例

逐步实现该需求, 先把基本的流程调通,这里我们先实现定义线程池数量的功能 ,代码如下

package com.artisan.test;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.stream.IntStream;
public class SimpleThreadPool {
    // 线程数
    private int size;
    // 默认线程数
    private static int DEFAULT_SIZE = 10;
    // 任务队列
    private final static LinkedList<Runnable> TASK_QUEUE = new LinkedList();
    // 工作线程集合
    private final static List<WorkTask> THREAD_QUEUE = new ArrayList<>();
    private static volatile int seq = 0;
    private static final ThreadGroup GROUP = new ThreadGroup("Pool_Group");
    private static final String THREAD_PREFIX = "SIMPLE_THREAD_POOL-";
    /**
     * 默认构造函数
     * 默认10个线程
     */
    public SimpleThreadPool() {
        this(DEFAULT_SIZE);
    }
    /**
     * 线程池中的线程数量
     *
     * @param size
     */
    public SimpleThreadPool(int size) {
        this.size = size;
        // 初始化
        init();
    }
    /**
     * 初始化
     */
    private void init() {
        for (int i = 0; i < size; i++) {
            createWorkTask();
        }
    }
    /**
     * 创建工作线程
     */
    private void createWorkTask() {
        // 创建工作线程
        WorkTask workTask = new WorkTask(GROUP, THREAD_PREFIX + (seq++));
        // 启动
        workTask.start();
        // 加入到工作线程集合
        THREAD_QUEUE.add(workTask);
    }
    /**
     * 将任务runnable 提交到 TASK_QUEUE
     *
     * @param runnable
     */
    public void submit(Runnable runnable) {
        synchronized (TASK_QUEUE) {
            // 添加到队列的最后面
            TASK_QUEUE.addLast(runnable);
            // 唤醒所有正在等待的线程
            TASK_QUEUE.notifyAll();
        }
    }
    /**
     * 线程状态
     */
    enum TaskState {
        FREE,
        RUNNING,
        BLOCKED,
        DEAD
    }
    /**
     * private 私有类
     * 继承Thread 的 工作线程
     */
    private static class WorkTask extends Thread {
        // 默认状态  FREE
        private volatile TaskState state = TaskState.FREE;
        public WorkTask(ThreadGroup threadGroup, String name) {
            super(threadGroup, name);
        }
        /**
         * 获取线程状态
         *
         * @return
         */
        public TaskState getTaskState() {
            return this.state;
        }
        /**
         * 重写run方法
         */
        @Override
        public void run() {
            // 跳出while的标识
            OUTER:
            // 只要不是DEAD 状态,一直从队列中获取消息
            while (state != TaskState.DEAD) {
                Runnable runnable;
                // 对队列进行加锁操作
                synchronized (TASK_QUEUE) {
                    // 如果队列为空,wait
                    while (TASK_QUEUE.isEmpty()) {
                        try {
                            // 更改状态
                            state = TaskState.BLOCKED;
                            // wait 放弃该锁
                            TASK_QUEUE.wait();
                        } catch (InterruptedException e) {
                            // 如果有个线程在wait,终止该线程会被InterruptedException异常捕获,
                            // break OUTER 跳出while循环,从而达到终止这个线程
                            break OUTER;
                        }
                    }
                    // TASK_QUEUE不为空 从队列中获取一个Runnable对象
                    // Removes and returns the first element from this list
                    runnable = TASK_QUEUE.removeFirst();
                }
                if (runnable != null) {
                    // 运行状态
                    state = TaskState.RUNNING;
                    // 运行
                    runnable.run();
                    // 运行结束后 置为FREE
                    state = TaskState.FREE;
                }
            }
        }
        /**
         * 关闭线程
         */
        public void close() {
            this.state = TaskState.DEAD;
        }
    }
    /**
     * 测试
     *
     * @param args
     */
    public static void main(String[] args) {
        SimpleThreadPool simpleThreadPool = new SimpleThreadPool();
//        for (int i = 0; i < 50; i++) {
//            simpleThreadPool.submit(()->{
//                try {
//                    System.out.println(Thread.currentThread().getName() + " is running" );
//                    Thread.sleep(1_000);
//                    System.out.println(Thread.currentThread().getName() + " finished" );
//                } catch (InterruptedException e) {
//                    e.printStackTrace();
//                }
//            });
//        }
        IntStream.range(0, 50)
                .forEach(i ->
                        simpleThreadPool.submit(() -> {
                            try {
                                System.out.println(Thread.currentThread().getName() +  "____" + i +  " start");
                                Thread.sleep(1_000);
                                System.out.println(Thread.currentThread().getName() + "____" + i +" finished");
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }));
    }
}


运行:

SIMPLE_THREAD_POOL-9____0 start
SIMPLE_THREAD_POOL-4____5 start
SIMPLE_THREAD_POOL-0____9 start
SIMPLE_THREAD_POOL-5____4 start
SIMPLE_THREAD_POOL-6____3 start
SIMPLE_THREAD_POOL-8____1 start
SIMPLE_THREAD_POOL-7____2 start
SIMPLE_THREAD_POOL-1____8 start
SIMPLE_THREAD_POOL-3____6 start
SIMPLE_THREAD_POOL-2____7 start
SIMPLE_THREAD_POOL-4____5 finished
SIMPLE_THREAD_POOL-6____3 finished
SIMPLE_THREAD_POOL-5____4 finished
SIMPLE_THREAD_POOL-3____6 finished
SIMPLE_THREAD_POOL-0____9 finished
SIMPLE_THREAD_POOL-9____0 finished
SIMPLE_THREAD_POOL-0____13 start
SIMPLE_THREAD_POOL-2____7 finished
SIMPLE_THREAD_POOL-5____12 start
SIMPLE_THREAD_POOL-1____8 finished
SIMPLE_THREAD_POOL-6____11 start
SIMPLE_THREAD_POOL-7____2 finished
SIMPLE_THREAD_POOL-4____10 start
SIMPLE_THREAD_POOL-8____1 finished
SIMPLE_THREAD_POOL-7____17 start
SIMPLE_THREAD_POOL-1____16 start
SIMPLE_THREAD_POOL-2____15 start
SIMPLE_THREAD_POOL-9____14 start
SIMPLE_THREAD_POOL-8____18 start
SIMPLE_THREAD_POOL-3____19 start
SIMPLE_THREAD_POOL-0____13 finished
SIMPLE_THREAD_POOL-0____20 start
SIMPLE_THREAD_POOL-5____12 finished
SIMPLE_THREAD_POOL-5____21 start
SIMPLE_THREAD_POOL-6____11 finished
SIMPLE_THREAD_POOL-6____22 start
SIMPLE_THREAD_POOL-4____10 finished
SIMPLE_THREAD_POOL-4____23 start
SIMPLE_THREAD_POOL-7____17 finished
SIMPLE_THREAD_POOL-7____24 start
SIMPLE_THREAD_POOL-1____16 finished
SIMPLE_THREAD_POOL-1____25 start
SIMPLE_THREAD_POOL-2____15 finished
SIMPLE_THREAD_POOL-2____26 start
SIMPLE_THREAD_POOL-9____14 finished
SIMPLE_THREAD_POOL-9____27 start
SIMPLE_THREAD_POOL-8____18 finished
SIMPLE_THREAD_POOL-8____28 start
SIMPLE_THREAD_POOL-3____19 finished
SIMPLE_THREAD_POOL-3____29 start
SIMPLE_THREAD_POOL-5____21 finished
SIMPLE_THREAD_POOL-2____26 finished
SIMPLE_THREAD_POOL-1____25 finished
SIMPLE_THREAD_POOL-7____24 finished
SIMPLE_THREAD_POOL-4____23 finished
SIMPLE_THREAD_POOL-0____20 finished
SIMPLE_THREAD_POOL-6____22 finished
SIMPLE_THREAD_POOL-0____35 start
SIMPLE_THREAD_POOL-4____34 start
SIMPLE_THREAD_POOL-7____33 start
SIMPLE_THREAD_POOL-1____32 start
SIMPLE_THREAD_POOL-8____28 finished
SIMPLE_THREAD_POOL-3____29 finished
SIMPLE_THREAD_POOL-2____31 start
SIMPLE_THREAD_POOL-9____27 finished
SIMPLE_THREAD_POOL-5____30 start
SIMPLE_THREAD_POOL-9____39 start
SIMPLE_THREAD_POOL-3____38 start
SIMPLE_THREAD_POOL-8____37 start
SIMPLE_THREAD_POOL-6____36 start
SIMPLE_THREAD_POOL-8____37 finished
SIMPLE_THREAD_POOL-2____31 finished
SIMPLE_THREAD_POOL-5____30 finished
SIMPLE_THREAD_POOL-3____38 finished
SIMPLE_THREAD_POOL-9____39 finished
SIMPLE_THREAD_POOL-6____36 finished
SIMPLE_THREAD_POOL-9____44 start
SIMPLE_THREAD_POOL-0____35 finished
SIMPLE_THREAD_POOL-4____34 finished
SIMPLE_THREAD_POOL-3____43 start
SIMPLE_THREAD_POOL-4____47 start
SIMPLE_THREAD_POOL-7____33 finished
SIMPLE_THREAD_POOL-7____48 start
SIMPLE_THREAD_POOL-5____42 start
SIMPLE_THREAD_POOL-1____32 finished
SIMPLE_THREAD_POOL-2____41 start
SIMPLE_THREAD_POOL-8____40 start
SIMPLE_THREAD_POOL-1____49 start
SIMPLE_THREAD_POOL-0____46 start
SIMPLE_THREAD_POOL-6____45 start
SIMPLE_THREAD_POOL-3____43 finished
SIMPLE_THREAD_POOL-5____42 finished
SIMPLE_THREAD_POOL-7____48 finished
SIMPLE_THREAD_POOL-4____47 finished
SIMPLE_THREAD_POOL-9____44 finished
SIMPLE_THREAD_POOL-6____45 finished
SIMPLE_THREAD_POOL-0____46 finished
SIMPLE_THREAD_POOL-1____49 finished
SIMPLE_THREAD_POOL-8____40 finished
SIMPLE_THREAD_POOL-2____41 finished


可知: 虽然定义了50个任务,但是根据日志来看,是由10个线程来完成的,符合预期。


相关文章
|
8天前
|
安全 Java 数据处理
Java并发编程:解锁多线程的潜力
在数字化时代的浪潮中,Java作为一门广泛使用的编程语言,其并发编程能力是提升应用性能和响应速度的关键。本文将带你深入理解Java并发编程的核心概念,探索如何通过多线程技术有效利用计算资源,并实现高效的数据处理。我们将从基础出发,逐步揭开高效并发编程的面纱,让你的程序运行得更快、更稳、更强。
|
7天前
|
存储 Java 调度
深入浅出Java线程池原理
本文深入分析了Java线程池的原理和实现,帮助读者更好地理解Java并发编程中线程池的创建、工作流程和性能优化。
|
6天前
|
安全 Java 数据库
一天十道Java面试题----第四天(线程池复用的原理------>spring事务的实现方式原理以及隔离级别)
这篇文章是关于Java面试题的笔记,涵盖了线程池复用原理、Spring框架基础、AOP和IOC概念、Bean生命周期和作用域、单例Bean的线程安全性、Spring中使用的设计模式、以及Spring事务的实现方式和隔离级别等知识点。
|
5天前
|
编解码 网络协议 API
Netty运行原理问题之Netty的主次Reactor多线程模型工作的问题如何解决
Netty运行原理问题之Netty的主次Reactor多线程模型工作的问题如何解决
|
7天前
|
安全 测试技术 调度
iOS开发-多线程编程
【8月更文挑战第12天】在iOS开发中,属性的内存管理至关重要,直接影响应用性能与稳定性。主要策略包括:`strong`(强引用),保持对象不被释放;`weak`(弱引用),不保持对象,有助于避免循环引用;`assign`(赋值),适用于基本数据类型及非指针对象类型;`copy`(复制),复制对象而非引用,确保不变性。内存管理基于引用计数,利用自动引用计数(ARC)自动管理对象生命周期。此外,需注意避免循环引用,特别是在block中。最佳实践包括理解各策略、避免不必要的强引用、及时释放不再使用的对象、注意block中的内存管理,并使用工具进行内存分析。正确管理内存能显著提升应用质量。
|
1天前
|
安全 C# 开发者
【C# 多线程编程陷阱揭秘】:小心!那些让你的程序瞬间崩溃的多线程数据同步异常问题,看完这篇你就能轻松应对!
【8月更文挑战第18天】多线程编程对现代软件开发至关重要,特别是在追求高性能和响应性方面。然而,它也带来了数据同步异常等挑战。本文通过一个简单的计数器示例展示了当多个线程无序地访问共享资源时可能出现的问题,并介绍了如何使用 `lock` 语句来确保线程安全。此外,还提到了其他同步工具如 `Monitor` 和 `Semaphore`,帮助开发者实现更高效的数据同步策略,以达到既保证数据一致性又维持良好性能的目标。
7 0
|
5天前
|
Java UED
基于SpringBoot自定义线程池实现多线程执行方法,以及多线程之间的协调和同步
这篇文章介绍了在SpringBoot项目中如何自定义线程池来实现多线程执行方法,并探讨了多线程之间的协调和同步问题,提供了相关的示例代码。
31 0
|
5天前
|
Java 程序员 调度
深入浅出Java多线程编程
Java作为一门成熟的编程语言,在多线程编程方面提供了丰富的支持。本文将通过浅显易懂的语言和实例,带领读者了解Java多线程的基本概念、创建方法以及常见同步工具的使用,旨在帮助初学者快速入门并掌握Java多线程编程的基础知识。
4 0
|
8天前
|
安全 Java API
揭秘Java并发编程的神秘面纱:线程安全与性能优化之间的微妙舞蹈,如何让你的程序在多核时代中翱翔!
【8月更文挑战第12天】随着多核处理器的普及,Java并发编程越发重要。线程安全确保多线程环境下的程序一致性,而性能优化则让程序高效运行。通过同步机制如`synchronized`关键字或`ReentrantLock`接口,我们可以实现线程安全,如在银行账户存款操作中限制并发访问。然而,过度同步会导致性能下降,因此采用细粒度锁和利用Java并发工具类(如`ConcurrentHashMap`)可提高程序的并发能力。理解这些概念并加以实践,是每个Java开发者提升技能的关键。
19 0
|
2月前
|
缓存 NoSQL Java
Java高并发实战:利用线程池和Redis实现高效数据入库
Java高并发实战:利用线程池和Redis实现高效数据入库
192 0