Ver código fonte

V0.3.3
1、添加了时间轮定时器的demo

Apple 5 meses atrás
pai
commit
00efb42775

+ 3 - 1
CMakeLists.txt

@@ -142,7 +142,9 @@ file(GLOB GLOBAL_SRC
 # add_subdirectory(${CMAKE_SOURCE_DIR}/demo/mqtt)
 # add_subdirectory(${CMAKE_SOURCE_DIR}/demo/http)
 # add_subdirectory(${CMAKE_SOURCE_DIR}/demo/threadPool)
-add_subdirectory(${CMAKE_SOURCE_DIR}/demo/ftp)
+# add_subdirectory(${CMAKE_SOURCE_DIR}/demo/ftp)
 # add_subdirectory(${CMAKE_SOURCE_DIR}/demo/OneThread)
+add_subdirectory(${CMAKE_SOURCE_DIR}/demo/timer)
+
 
 

+ 0 - 312
demo/threadPool/ThreadPool.cpp

@@ -1,312 +0,0 @@
-#include "ThreadPool.h"
-
-#include "spdlog/spdlog.h"
-#include "fmt/std.h"
-
-/**
- * @brief Construct a new Thread Pool:: Thread Pool object
- *        构造函数,从这里创建线程,和Linux C的线程池不同,Linux C的线程池数组管理的是线程ID,
- *        而C++的线程数组直接存储的就是线程函数体,里面有个function的变量,指向任务队列中任务函数
- * 
- * @param numThread 
- */
-ThreadPool::ThreadPool() : 
-    m_stop(false)
-{
-
-    /* 初始化变量 */
-    m_threadMaxNum = std::thread::hardware_concurrency();   /* 根据CPU核心数规定线程数目 */
-    m_threadMiniNum = 3;
-    m_threadLiveNum = 0;
-    m_threadExitNum = 0;
-    m_threadAddNum = 5;
-    m_threadMiniIdle = 2;
-    m_threadMaxIdle = 6;
-    m_threadRunNum = 0;
-
-    /* 创建管理线程,this表示是这个类的成员函数 */
-    m_managerThread = std::thread(&ThreadPool::managerThread, this);
-
-    SPDLOG_DEBUG("***** Hello ThreadPool *****");
-
-    // /* 创建初始的numThread个线程 */
-    // createThread(numThread);
-}
-/* 析构函数 */
-ThreadPool::~ThreadPool()
-{
-    SPDLOG_INFO("线程池正在退出...");
-    /* 将stop置为true */
-    {
-        std::unique_lock<std::mutex> lock(m_mutexTask);
-        m_stop = true;
-    }
-
-    SPDLOG_INFO("通知所有工作线程退出...");
-    /* 发送条件变量,通知所有线程 */
-    m_cond_Task.notify_all();
-    /* 等待所有的线程退出并回收完成 */
-    while (!m_mapThreads.empty())
-    {
-        /* 管理线程自己退出了,所以要手动清空容器 */
-        clearThread();
-        std::this_thread::sleep_for(std::chrono::milliseconds(100));
-    }
-
-    SPDLOG_INFO("回收管理线程...");
-    /* 先回收管理线程 */
-    m_managerThread.join();
-    SPDLOG_INFO("===== 线程池退出完成 =====");
-}
-
-
-/* 工作线程函数 */
-void ThreadPool::worker()
-{
-    m_threadLiveNum++;
-    while (true)
-    {
-        /* 等待任务队列中有任务 */
-        std::unique_lock<std::mutex> lock(m_mutexTask);
-        /* 这里的wait第二个参数是lamba表达式,在唤醒后会进行判断是否满足条件 */
-        m_cond_Task.wait(lock, [this]
-                               { return !m_queue_Tasks.empty() || m_stop ||
-                                        (m_threadExitNum > 0); });
-        /* 任务队列中有任务了,条件变量被唤醒了,先判断是不是需要结束线程 */
-        if (m_stop && m_queue_Tasks.empty())
-        {
-            break;
-        }
-        /* 判断是不是需要销毁多余的线程 */
-        if (m_threadExitNum.load() > 0 )
-        {
-            m_threadExitNum--;
-            /* 再次判断有没有新任务,有就不退出 */
-            if ( m_queue_Tasks.empty())
-            {
-                break;
-            }
-        }
-        /* 取出任务,执行任务 */
-        std::function<void()> task(std::move(m_queue_Tasks.front()));
-        m_queue_Tasks.pop();  /* 取出的任务出队 */
-        lock.unlock();              /* 解锁任务队列 */
-        m_threadRunNum++;     /* 更新线程状态数 */
-        /* 开始执行任务 */
-        task();
-        m_threadRunNum--;         /* 更新线程状态数 */
-    }
-
-    /* 线程结束 */
-    m_threadLiveNum--;
-    /* 将自身ID加入到退出列表中 */
-    {
-        std::unique_lock<std::mutex> lock(m_mutexExitThreadID);
-        m_exitThreadID.emplace_back(std::this_thread::get_id());
-    }
-    /* 使用流将线程ID转换成字符串,不然fmt无法打印 */
-    std::stringstream ss;
-    ss << std::this_thread::get_id();
-    SPDLOG_DEBUG("线程ID:{}退出任务循环", ss.str());
-
-    return;
-}
-
-
-/**
- * @brief 管理者线程,维护线程创建或死亡
- * 
- */
-void ThreadPool::managerThread()
-{
-    while (!m_stop)
-    {
-        /* 获取空闲线程的个数 */
-        int num_idle = m_threadLiveNum.load() - m_threadRunNum.load();
-        /* 判断线程是否够用,是否需要创建新的线程 */
-        // SPDLOG_DEBUG("***** 判断是否需要添加线程 *****");
-        if ((num_idle < m_threadMiniIdle.load()) && (m_threadLiveNum.load() < m_threadMaxNum) )
-        {
-            std::unique_lock<std::mutex> lock(m_mutexTask);
-            int numTask = (int)m_queue_Tasks.size();            /* 获取任务队列中的任务个数 */
-            lock.unlock();
-            int numAdd = 0;
-            if(numTask > 0)
-            {
-                /* 任务数 + 存在的线程个数是否大于最大线程数 */
-                if( numTask + m_threadLiveNum.load() <= m_threadMaxNum )
-                {
-                    /* 创建numTask个线程 */
-                    numAdd = numTask;
-                }
-                /* 默认添加的个数 + 存在的线程数是否大于最大线程数 */
-                else if ( (m_threadAddNum.load() + m_threadLiveNum.load()) <= m_threadMaxNum)
-                {
-                    /* 创建m_threadAddNum个线程 */
-                    numAdd = m_threadAddNum.load();
-                }
-                /* 能添加几个线程就添加几个线程 */
-                else
-                {
-                    numAdd = m_threadMaxNum - m_threadLiveNum.load();
-                }
-            }
-            /* 空闲线程数低于设置的最小空闲线程数 */
-            else
-            {
-                numAdd = m_threadMiniIdle.load() - num_idle;
-            }
-            
-            if(numAdd > 0)
-            {
-                SPDLOG_INFO("需要添加{}个线程", numAdd);
-                createThread(numAdd);
-                continue;   /* 直接下一个循环,无需检查需不需要销毁线程 */
-            }
-            
-        }
-
-        /* 判断空闲线程是否过多,是否需要销毁几个线程 */
-        // SPDLOG_DEBUG("***** 判断是否需要销毁线程 *****");
-        /* 由于没规定每次销毁的线程个数,所以这里使用m_threadAddNum作为每次销毁的标准个数 */
-        if (num_idle > m_threadMaxIdle.load())
-        {
-            int num_Exit = num_idle = m_threadMaxIdle.load();
-            if (num_Exit > m_threadAddNum.load())
-            {
-                num_Exit = m_threadAddNum.load();
-            }
-            m_threadExitNum.exchange(num_Exit);
-
-            SPDLOG_INFO("有{}个线程需要退出", m_threadExitNum.load());
-            /* 唤醒需要退出的num_idle个线程 */
-            for (int i = 0; i < num_Exit; i++)
-            {
-                m_cond_Task.notify_one();
-            }
-        }
-        /* 回收退出的线程 */
-        clearThread();
-
-        // SPDLOG_INFO("线程池中的线程实例个数:{}", m_threads.size());
-        std::this_thread::sleep_for(std::chrono::seconds(1));
-    }
-    SPDLOG_INFO("管理线程退出...");
-}
-
-/**
- * @brief 创建新的线程
- *        注意:这里只能使用lambda表达式,或者将do_work变成全局函数,emplace_back会调用thread构造函数将lambda表达式构造成一个std::thread实例
- *        lambda表达式里是子线程,外面是主线程
- * 
- */
-void ThreadPool::createThread(int num)
-{
-    for (int i = 0; i < num; i++)
-    {
-        /* 创建线程,传入工作函数 */
-        std::thread t(&ThreadPool::worker, this);
-        m_mapThreads.insert(std::make_pair( t.get_id(), std::move(t) ));
-    }
-}
-
-/**
- * @brief 删除线程池中失效的线程实例,使用递归的方法遍历全部
- * 
- */
-void ThreadPool::clearThread()
-{
-    for(auto& it : m_exitThreadID)
-    {
-        auto it1 = m_mapThreads.find(it);
-        if(it1 != m_mapThreads.end())
-        {
-            if(it1->second.joinable())
-            {
-                it1->second.join();
-                m_mapThreads.erase(it1);
-            }
-        }
-    }
-    m_exitThreadID.clear();
-}
-
-
-
-/* 获取线程池最大线程的个数 */
-int ThreadPool::getThreadMaxNum()
-{
-    return m_threadMaxNum;
-}
-
-/* 设置线程池最大线程的个数 */
-void ThreadPool::setThreadMaxNum(int num)
-{
-    m_threadMaxNum = num;
-}
-
-/* 获取线程池最大线程的个数 */
-int ThreadPool::getThreadMiniNum()
-{
-    return m_threadMiniNum;
-}
-
-/* 设置线程池最大线程的个数 */
-void ThreadPool::setThreadMiniNum(int num)
-{
-    m_threadMiniNum = num;
-}
-
-/* 获取线程池空闲线程的个数 */
-int ThreadPool::getThreadIdleNum()
-{
-    return m_threadLiveNum.load() - m_threadRunNum.load();
-}
-
-/* 获取线程池正在运行的线程个数 */
-int ThreadPool::getThreadRunNum()
-{
-    return m_threadRunNum.load();
-}
-
- /* 获取线程池现存的线程个数 */
-int ThreadPool::getThreadLiveNum()
-{
-    return m_threadLiveNum.load();
-}
-
-/* 线程池每次创建线程的个数 */
-int ThreadPool::getThreadAddNum()
-{
-    return m_threadAddNum.load();
-}
-
-/* 设置线程池每次创建线程的个数 */
-void ThreadPool::setThreadAddNum(int num)
-{
-    m_threadAddNum.exchange(num);
-}
-
-/* 线程池最小空闲线程的个数 */
-int ThreadPool::getThreadMiniIdle()
-{
-    return m_threadMiniIdle.load();
-}
-
-/* 设置线程池最小空闲线程的个数 */
-void ThreadPool::setThreadMiniIdle(int num)
-{
-    m_threadMiniIdle.exchange(num);
-}
-
-/* 线程池最大空闲线程的个数 */
-int ThreadPool::getThreadMaxIdle()
-{
-    return m_threadMaxIdle.load();
-}
-
-/* 设置线程池最大空闲线程的个数 */
-void ThreadPool::setThreadMaxIdle(int num)
-{
-    m_threadMaxIdle.exchange(num);
-}

+ 0 - 134
demo/threadPool/ThreadPool.h

@@ -1,134 +0,0 @@
-#ifndef THREADPOOL_H
-#define THREADPOOL_H
-
-#include <list>
-#include <thread>
-#include <condition_variable>
-#include <queue>
-#include <functional>
-#include <atomic>
-#include <map>
-#include <future>
-
-// #include "spdlog/spdlog.h"
-// #include "fmt/std.h"
-
-/**
- * @brief   1、在ThreadPool类中重新封装了一个OneThread类,类中有线程实例和相关的接口,每个OneThread实例就是一个线程
- *          2、采用可变参数模板函数添加任务到任务队列中
- *          3、线程池采用单例模式
- * 
- */
-
-class ThreadPool
-{
-private:
-    ThreadPool();
-    ThreadPool(const ThreadPool &tp) = delete;
-    ThreadPool &operator=(const ThreadPool &tp) = delete;
-
-
-public:
-    
-    static ThreadPool& getInstance()
-    {
-        static ThreadPool tp;
-        return tp;
-    }
-
-    ~ThreadPool();
-
-    /**
-     * @brief 向任务队列添加任务函数
-     * 
-     * @tparam F 函数(指针?)
-     * @tparam Args 参数包
-     * @param f 万能引用
-     * @param args 万能引用
-     */
-    template <typename F, typename... Args>
-    void add_task(F &&f, Args &&...args)
-    {
-        /* 将函数参数和函数绑定 */
-        std::function<void()> task = std::bind(std::forward<F>(f), std::forward<Args>(args)...);
-        /* 作用域是用于解锁lock */
-        {
-            std::unique_lock<std::mutex> lock(m_mutexTask);
-            m_queue_Tasks.emplace(std::move(task));         /* 入队 */
-        }
-        /* 唤醒一个线程 */
-        m_cond_Task.notify_one();
-    }
-
-    /* 添加带有返回值的任务函数
-     * future内部定义了一个类型std::result_of<F(Args...)>::Type */
-    template<typename F, typename... Args>
-    auto add_task_with_ret(F&& f, Args&&... args) -> std::future<typename std::result_of<F(Args...)>::type>
-    {
-        /* 将类型去一个别名 */
-        using  resultType = typename std::result_of<F(Args...)>::type;
-        /* 将传入的函数与参数绑定并包装成一个可调用的指针,使用智能指针管理 */
-        auto task = std::make_shared<std::packaged_task<resultType()>>(
-            /* 使用forward完美转发,防止右值变成了左值 */
-            std::bind(std::forward<F>(f), std::forward<Args>(args)...)
-        );
-        /* 获取future对象,用于获取返回值 */
-        std::future<resultType> res = task->get_future();
-        {
-            std::unique_lock<std::mutex> lock(m_mutexTask);
-            /* 使用lamba表达式调用封装的函数 */
-            m_queue_Tasks.emplace([task](){
-                (*task)();
-            });
-        }
-        /* 解锁条件变量 */
-        m_cond_Task.notify_one();
-        /* 返回值,函数调用完成后,可以通过这个返回值获取任务的返回值 */
-        return res;
-    }
-
-    /******  获取当前线程池在运行的线程个数,空闲线程的个数  ******/
-    int getThreadMaxNum();                      /* 获取线程池最大线程的个数 */
-    void setThreadMaxNum(int num);              /* 设置线程池最大线程的个数 */
-    int getThreadMiniNum();                     /* 获取线程池最小线程的个数 */
-    void setThreadMiniNum(int num);             /* 设置线程池最小线程的个数 */
-    int getThreadIdleNum();                     /* 获取线程池空闲线程的个数 */
-    int getThreadRunNum();                      /* 获取线程池正在运行的线程个数 */
-    int getThreadLiveNum();                     /* 获取线程池现存的线程个数 */
-    int getThreadAddNum();                      /* 线程池每次创建线程的个数 */
-    void setThreadAddNum(int num);              /* 设置线程池每次创建线程的个数 */
-    int getThreadMiniIdle();                    /* 线程池最小空闲线程的个数 */
-    void setThreadMiniIdle(int num);            /* 设置线程池最小空闲线程的个数 */
-    int getThreadMaxIdle();                     /* 线程池最大空闲线程的个数 */
-    void setThreadMaxIdle(int num);             /* 设置线程池最大空闲线程的个数 */
-
-private:
-    void worker();                              /* 工作线程函数 */
-    void managerThread();                       /* 维护线程池的线程,如提前创建线程,销毁线程 */
-    void createThread(int num);                 /* 创建新的线程 */
-    void clearThread();                         /* 清除失效的线程实例 */
-
-private:
-    class OneThread;                                    /* 类声明 */
-    std::map<std::thread::id, std::thread> m_mapThreads;/* 线程数组,维护线程池 */
-    std::list<std::thread::id> m_exitThreadID;          /* 已经退出任务函数的线程ID */
-    std::queue<std::function<void(void)>> m_queue_Tasks;/* 任务队列,任务函数都是无返回值的函数 */
-    std::condition_variable m_cond_Task;                /* 条件变量,没有任务的时候阻塞住 */
-
-    bool m_stop;                                        /* 线程是否停止 */
-    std::mutex m_mutexExitThreadID;                     /* 互斥锁,搭配环境变量使用,对已经退出的线程ID上锁 */
-    std::mutex m_mutexTask;                             /* 互斥锁,搭配环境变量使用,对任务队列上锁 */
-    std::thread m_managerThread;                        /* 管理线程 */
-
-    int m_threadMaxNum = 256;                               /* 默认最大线程数 */
-    int m_threadMiniNum = 5;                                /* 默认线程池中最小线程数 */
-    std::atomic<int> m_threadRunNum;                        /* 正在运行的线程个数 */
-    std::atomic<int> m_threadLiveNum;                       /* 现有的线程个数 */
-    std::atomic<int> m_threadExitNum;                       /* 需要销毁的线程个数 */
-    std::atomic<int> m_threadAddNum;                        /* 每次需要添加的线程个数 */
-    std::atomic<int> m_threadMiniIdle;                      /* 如果空闲线程小于这个数,就添加m_ThreadAddNum个线程 */
-    std::atomic<int> m_threadMaxIdle;                       /* 最大空闲的线程个数,超过这个个数一定时间,就会销毁多余的 */
-
-};
-
-#endif /* THREADPOOL_H */

+ 79 - 0
demo/timer/CMakeLists.txt

@@ -0,0 +1,79 @@
+cmake_minimum_required(VERSION 3.5)
+
+set(this_exe timer)
+
+
+#包含源文件
+file(GLOB LOCAL_SRC
+    ${CMAKE_CURRENT_SOURCE_DIR}/*.qrc
+    ${CMAKE_CURRENT_SOURCE_DIR}/*.rc
+    ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/*.ui
+
+    ${CMAKE_SOURCE_DIR}/External/common/LightLog/*.cpp
+    ${CMAKE_SOURCE_DIR}/External/common/Logs/*.cpp
+    ${CMAKE_SOURCE_DIR}/External/common/ThreadPool/*.cpp
+    
+)
+
+
+# 生成可执行程序
+
+add_executable(${this_exe}
+    # WIN32
+    ${GLOBAL_SRC}
+    ${LOCAL_SRC} 
+)
+
+
+#添加头文件
+target_include_directories(${this_exe} PRIVATE
+
+    ${CMAKE_CURRENT_SOURCE_DIR}
+    ${CMAKE_SOURCE_DIR}/External/common/LightLog
+    ${CMAKE_SOURCE_DIR}/External/common/Logs
+    ${CMAKE_SOURCE_DIR}/External/common/FmtLog
+    ${CMAKE_SOURCE_DIR}/External/common/Timer
+    ${CMAKE_SOURCE_DIR}/External/common/ThreadPool
+    ${CMAKE_SOURCE_DIR}/External/common/RingQueue
+)
+
+target_link_libraries(${this_exe} PRIVATE
+    Qt5::Widgets
+    Qt5::Core
+    Qt5::Network
+    # Qt5::Multimedia
+    # Qt5::Xml
+    # Qt5::Sql
+)
+
+target_link_libraries(${this_exe} PRIVATE 
+    fmt::fmt
+    spdlog::spdlog
+    ${CURL_LIBRARY}
+)
+
+if(CMAKE_CXX_COMPILER_VERSION LESS 9.0)
+    target_link_libraries(${this_exe} PRIVATE
+        stdc++fs
+    )
+endif()
+
+# target_link_libraries(${this_exe} PRIVATE
+#     ${CURL_LIBRARY}
+    
+# )
+# message(STATUS "CURL_LIBRARY: ${CURL_LIBRARY}")
+
+
+# if(CMAKE_CXX_COMPILER_ID MATCHES MSVC)
+#     target_link_libraries(${this_exe} PRIVATE
+#         # debug spdlogd.lib
+#         # optimized spdlog.lib
+#     )
+# elseif(CMAKE_CXX_COMPILER_ID MATCHES GNU)
+#     target_link_libraries(${this_exe} PRIVATE
+#         # debug 
+#         # optimized ${SM_DLL}
+#     )
+# endif()

+ 14 - 0
demo/timer/main.cpp

@@ -0,0 +1,14 @@
+#include "widget.h"
+
+#include <QApplication>
+#include "loginit.h"
+
+
+int main(int argc, char *argv[])
+{
+    QApplication a(argc, argv);
+    init_log();
+    Widget w;
+    w.show();
+    return a.exec();
+}

+ 54 - 0
demo/timer/widget.cpp

@@ -0,0 +1,54 @@
+#include "widget.h"
+#include "./ui_widget.h"
+
+#include <QTimer>
+
+#include "spdlog/spdlog.h"
+#include "fmtlog.h"
+#include "LightLog.h"
+
+
+Widget::Widget(QWidget *parent)
+    : QWidget(parent)
+    , ui(new Ui::Widget)
+{
+    ui->setupUi(this);
+
+
+    SPDLOG_INFO("***** Qt Library *****");
+}
+
+Widget::~Widget()
+{
+
+    delete ui;
+}
+
+
+void Widget::on_pBtn_connect_clicked()
+{
+    SPDLOG_INFO("点击了“连接按钮”");
+    std::vector<std::string> list;
+}
+
+
+
+void Widget::on_pBtn_downloadFile_clicked()
+{
+    SPDLOG_INFO("点击了“下载文件”");
+
+}
+
+void Widget::on_pBtn_downloadVideo_clicked()
+{
+    SPDLOG_INFO("点击了“下载视频”");
+
+   
+}
+
+void Widget::on_pBtn_logSpeed_clicked()
+{
+    SPDLOG_INFO("点击了“日志速度”");
+    
+}
+

+ 32 - 0
demo/timer/widget.h

@@ -0,0 +1,32 @@
+#ifndef WIDGET_H
+#define WIDGET_H
+
+#include <QWidget>
+
+QT_BEGIN_NAMESPACE
+namespace Ui { class Widget; }
+QT_END_NAMESPACE
+
+class Widget : public QWidget
+{
+    Q_OBJECT
+
+public:
+    Widget(QWidget *parent = nullptr);
+    ~Widget();
+
+private slots:
+
+    void on_pBtn_connect_clicked();
+
+    void on_pBtn_downloadFile_clicked();
+
+    void on_pBtn_downloadVideo_clicked();
+
+    void on_pBtn_logSpeed_clicked();
+
+private:
+    Ui::Widget *ui;
+
+};
+#endif // WIDGET_H

+ 62 - 0
demo/timer/widget.ui

@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>Widget</class>
+ <widget class="QWidget" name="Widget">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>800</width>
+    <height>600</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Widget</string>
+  </property>
+  <widget class="QWidget" name="widget_pBtn" native="true">
+   <property name="geometry">
+    <rect>
+     <x>30</x>
+     <y>30</y>
+     <width>681</width>
+     <height>311</height>
+    </rect>
+   </property>
+   <layout class="QGridLayout" name="gridLayout">
+    <item row="0" column="1">
+     <widget class="QPushButton" name="pBtn_downloadFile">
+      <property name="text">
+       <string>下载文件</string>
+      </property>
+     </widget>
+    </item>
+    <item row="0" column="0">
+     <widget class="QPushButton" name="pBtn_connect">
+      <property name="text">
+       <string>连接</string>
+      </property>
+     </widget>
+    </item>
+    <item row="2" column="0" colspan="2">
+     <widget class="QLineEdit" name="lineEdit"/>
+    </item>
+    <item row="1" column="0">
+     <widget class="QPushButton" name="pBtn_downloadVideo">
+      <property name="text">
+       <string>下载视频</string>
+      </property>
+     </widget>
+    </item>
+    <item row="1" column="1">
+     <widget class="QPushButton" name="pBtn_logSpeed">
+      <property name="text">
+       <string>日志速度对比</string>
+      </property>
+     </widget>
+    </item>
+   </layout>
+  </widget>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>

+ 12 - 0
功能添加说明.md

@@ -0,0 +1,12 @@
+
+
+# 功能添加说明
+
+## 定时器(基于时间轮)
+1. 采用多线程运行任务
+2. 修改定时方式,等将任务发送给线程池执行了再计算下一次时间,不再是一次将时间计算完成,这样可以解决到达时间点末尾定时可能不准的问题
+3. 定时器改为单例模式,定时器要占用一个线程,全局都使用这个定时器,避免浪费资源
+
+## 线程池
+1. 添加优先级模式,定时器添加的任务函数可以选择设置为高优先级,没有空闲线程就创建执行
+2. 新增一个队列,用于存放优先级高的任务函数