对于线程池的理解

线程池

线程池的目的

什么是线程池:

线程池的基本思想是一种对象池,在程序启动时就开辟一块内存空间,里面存放了众多(未死亡)的线程,池中线程执行调度由池管理器来处理。当有线程任务时,从池中取一个,执行完成后线程对象归池,这样可以避免反复创建线程对象所带来的性能开销,节省了系统的资源。

线程池的好处:

1、能够在某些情况下动态的调整工作线程的数量

2、可以大量节省系统频繁的创建和销毁线程所需要的资源

3、提高响应速度

线程池的组成:

1、线程池管理器(ThreadPoolManager):

用于创建并管理线程池 包括创建线程,销毁线程池,添加任务

2、工作线程(WorkThread):

线程池中线程,在没有任务时处于等待状态,可以循环的执行任务

3、任务接口(Task):

每个任务必须实现的接口,以供工作线程调度任务的执行。它规定了任务的入口,任务执行完后的收尾工作,任务的执行状态等;

4、任务队列:用于存放没有处理的任务。提供一种缓冲机制。

如何创建一个线程池?

Java中提供了创建线程程池的一个类:Executor

创建时,一般使用它的子类即:ThreadPoolExector

在这里插入图片描述
在这里插入图片描述

线程池中的corePoolSize就是线程池中的核心线程数量,这几个核心线程,只是在没有用的时候,也不会被回收,maximumPoolSize就是线程池中可以容纳的最大线程的数量,而keepAliveTime,就是线程池中除了核心线程之外的其他的最长可以保留的时间,因为在线程池中,除了核心线程即使在无任务的情况下也不能被清除,其余的都是有存活时间的,意思就是非核心线程可以保留的最长的空闲时间,而util,就是计算这个时间的一个单位,workQueue,就是等待队列,任务可以储存在任务队列中等待被执行,执行的是FIFIO原则(先进先出)。threadFactory,就是创建线程的线程工厂,最后一个handler,是一种拒绝策略,我们可以在任务满了之后,拒绝执行某些任务。

在这里插入图片描述

任务进来时,首先执行判断,判断核心线程是否处于空闲状态,如果不是,核心线程就先就执行任务,如果核心线程已满,则判断任务队列是否有地方存放该任务,若果有,就将任务保存在任务队列中,等待执行,如果满了,在判断最大可容纳的线程数,如果没有超出这个数量,就开创非核心线程执行任务,如果超出了,就调用handler实现拒绝策略。

handler的拒绝策略:

有四种:第一种AbortPolicy:不执行新任务,直接抛出异常,提示线程池已满这是默认使用的拒绝策略

​ 第二种DisCardPolicy:不执行新任务,也不抛出异常

​ 第三种DisCardOldSetPolicy:将消息队列中的第一个任务替换为当前新进来的任务执行

​ 第四种CallerRunsPolicy:直接调用execute来执行当前任务

线程池的种类

四种常见的线程池:

CachedThreadPool:可缓存的线程池,该线程池中没有核心线程,非核心线程的数量为Integer.max_value,就是无限大,当有需要时创建线程来执行任务,没有需要时回收线程,适用于量大但小而轻的任务。

SecudleThreadPool:周期性执行任务的线程池,按照某种特定的计划执行线程中的任务,有核心线程,但也有非核心线程,非核心线程的大小也为无限大。适用于执行周期性的任务。

SingleThreadPool:只有一条线程来执行任务一个线程消亡会有一个新的线程代替,适用于有顺序的任务的应用场景适用于任务单一要求顺序的任务。

FixedThreadPool:定长的线程池,有核心线程,核心线程的即为最大的线程数量,没有非核心线程适用于负载重

线程池的基本实现:

  1. 线程池接口类 ThreadPool

    ``

    import java.util.List;
    
    /**
     * Desc:线程池接口类
     */
    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

    ``

    import java.util.Arrays;
    import java.util.List;
    import java.util.Queue;
    import java.util.concurrent.ConcurrentLinkedQueue;
    import java.util.concurrent.atomic.AtomicLong;
    
    /**
     * Desc:线程池实现类
     */
    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;
            }
        }
    }
    
  3. 自定义任务类Task.java

    ``

    /**
     * Desc:自定义任务类
     */
    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. 线程池测试类

    ``

    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * Desc:线程池测试类
     */
    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);
        }
    }
    

核心参数的意义

public ThreadPoolExecutor(int corePoolSize,

​ int maximumPoolSize, //可以容纳的最大线程的数量

​ long keepAliveTime, //非核心线程可以保留的空闲时间

​ TimeUnit unit, //计算空闲时间的单位

​ BlockingQueue workQueue, //等待队列

​ ThreadFactory threadFactory, //创建线程的线程工厂

​ RejectedExecutionHandler handler//拒绝策略,任务满了之后拒绝执行某些任务
)

核心方法讲解

AbstractExecutorService抽象类的基本属性

AbstractExecutorService是个抽象类主要是对ExecutorService接口方法的一些实现。

  private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0)); 
 //这个状态位是来记录workerCount和runState的值,高三位是运行状态,低29位是workerCount的值
 
  private static final int COUNT_BITS = Integer.SIZE - 3; // 29
  private static final int CAPACITY   = (1 << COUNT_BITS) - 1; //容量 2^29 -1 
 
     // 表示线程池可以接受新的任务,并且处理阻塞队列当中的任务
    private static final int RUNNING    = -1 << COUNT_BITS;
    // 不接受新的任务,但是会去处理阻塞队列当中的任务
    private static final int SHUTDOWN   =  0 << COUNT_BITS; 
   
    // 不接受新的任务,不处理队列当中的任务,中止正在运行中的任务
    private static final int STOP       =  1 << COUNT_BITS; 
 
    // 所有的任务都中止了,workCount变为0,并且会去执行terminated方法
    private static final int TIDYING    =  2 << COUNT_BITS; 
 
 
    // 在TIDYING状态的基础上,执行完了terminated方法
    private static final int TERMINATED =  3 << COUNT_BITS; 
 
    private final BlockingQueue<Runnable> workQueue; // 阻塞队列
 
    private final ReentrantLock mainLock = new ReentrantLock(); 
 
 private final HashSet<Worker> workers = new HashSet<Worker>(); //存放执行的任务
 
 private final Condition termination = mainLock.newCondition(); //终止条件
 
//线程池执行过得最大线程数 
private int largestPoolSize; 
 
//已经完成的线程数
 private long completedTaskCount; 
 
//创建线程的线程工厂
private 
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在信号处理领域,DOA(Direction of Arrival)估计是一项关键技术,主要用于确定多个信号源到达接收阵列的方向。本文将详细探讨三种ESPRIT(Estimation of Signal Parameters via Rotational Invariance Techniques)算法在DOA估计中的实现,以及它们在MATLAB环境中的具体应用。 ESPRIT算法是由Paul Kailath等人于1986年提出的,其核心思想是利用阵列数据的旋转不变性来估计信号源的角度。这种算法相比传统的 MUSIC(Multiple Signal Classification)算法具有较低的计算复杂度,且无需进行特征值分解,因此在实际应用中颇具优势。 1. 普通ESPRIT算法 普通ESPRIT算法分为两个主要步骤:构造等效旋转不变系统和估计角度。通过空间平移(如延时)构建两个子阵列,使得它们之间的关系具有旋转不变性。然后,通过对子阵列数据进行最小二乘拟合,可以得到信号源的角频率估计,进一步转换为DOA估计。 2. 常规ESPRIT算法实现 在描述中提到的`common_esprit_method1.m`和`common_esprit_method2.m`是两种不同的普通ESPRIT算法实现。它们可能在实现细节上略有差异,比如选择子阵列的方式、参数估计的策略等。MATLAB代码通常会包含预处理步骤(如数据归一化)、子阵列构造、旋转不变性矩阵的建立、最小二乘估计等部分。通过运行这两个文件,可以比较它们在估计精度和计算效率上的异同。 3. TLS_ESPRIT算法 TLS(Total Least Squares)ESPRIT是对普通ESPRIT的优化,它考虑了数据噪声的影响,提高了估计的稳健性。在TLS_ESPRIT算法中,不假设数据噪声是高斯白噪声,而是采用总最小二乘准则来拟合数据。这使得算法在噪声环境下表现更优。`TLS_esprit.m`文件应该包含了TLS_ESPRIT算法的完整实现,包括TLS估计的步骤和旋转不变性矩阵的改进处理。 在实际应用中,选择合适的ESPRIT变体取决于系统条件,例如噪声水平、信号质量以及计算资源。通过MATLAB实现,研究者和工程师可以方便地比较不同算法的效果,并根据需要进行调整和优化。同时,这些代码也为教学和学习DOA估计提供了一个直观的平台,有助于深入理解ESPRIT算法的工作原理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值