加入收藏 | 设为首页 | 会员中心 | 我要投稿 我爱制作网_沈阳站长网 (https://www.024zz.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 服务器 > 搭建环境 > Linux > 正文

四大经典案例_线程池及java代码实现

发布时间:2022-11-18 11:11:18 所属栏目:Linux 来源:
导读:  大家好,我是bug郭,一名双非科班的在校大学生。对C/JAVA、数据结构、Linux及MySql、算法等领域感兴趣,喜欢将所学知识写成博客记录下来。 希望该文章对你有所帮助!如果有错误请大佬们指正!共同学习交流

  
  大家好,我是bug郭,一名双非科班的在校大学生。对C/JAVA、数据结构、Linux及MySql、算法等领域感兴趣,喜欢将所学知识写成博客记录下来。 希望该文章对你有所帮助!如果有错误请大佬们指正!共同学习交流
 
  线程池
 
  我们之前学过常量池!这里的线程池也大同小异!
 
  我们通过创建很多个线程放在一块空间不进行销毁,等到需要的时候就启动线程!避免了创建销毁的时间开销! 提高开发效率!
 
  我们之前不是说一个线程创建并不会划分很多时间吗! 但是我们的多线程编程,有时候需要使用到很多很多线程,如果要进行创建,效率就不高,而线程池或者协程(我们后面会介绍)就避免了创建销毁线程! 但我们需要用到线程时,自己从线程池中给出就好!
 
  我们创建线程的本质还是要通过内核态(就是我们的操作系统)进行创建,然而内核态创建的时间,我们程序员无法掌控,而通过线程池,我们就可以避免了内核态的操作,直接在用户态,进行线程的调用,也就是应用程序层!
 
  使用线程池大大提高了我们的开发效率!
 
  我们来学习一下java中给我们提供的线程池类,然后自己实现一个线程池!
 
  ThreadPoolExecutor 线程池
 
  这个类在java.util.concurrent并发编程包下,我们用到的很多关于并发编程的类都在!
 
  可以看到这个线程池有4个构造方法!
 
  在这里插入图片描述
 
  我们了解一下参数最多的那个方法!
 
  public ThreadPoolExecutor(int corePoolSize,
                            int maximumPoolSize,
                            long keepAliveTime,
                            TimeUnit unit,
                            BlockingQueue<Runnable> workQueue,
                            ThreadFactory threadFactory,
                            RejectedExecutionHandler handler)
  创建一个新的 ThreadPoolExecutor与给定的初始参数。
  参数
      corePoolSize - 即使空闲时仍保留在池中的线程数,除非设置 allowCoreThreadTimeOut
      maximumPoolSize - 池中允许的最大线程数
      keepAliveTime - 当线程数大于内核时,这是多余的空闲线程在终止前等待新任务的最大时间。
      unit - keepAliveTime参数的时间单位
      workQueue - 用于在执行任务之前使用的队列。 这个队列将仅保存execute方法提交的Runnable任务。
      threadFactory - 执行程序创建新线程时使用的工厂
      handler - 执行被阻止时使用的处理程序,因为达到线程限制和队列容量
  我们这里的线程池类比一个公司,便于我们理解该类
 
  可以看到java给我们提供的这个线程池类让人头大!
 
  但是不必焦虑,我们只需要知道int maximumPoolSize,
 
  核心线程数和 maximumPoolSize 池中允许的最大线程数即可!
 
  面试问题
 
  思考一个问题
 
  我们有一个程序需要多线程并发处理一些任务,使用线程池的话,需要设置多大的线程数?
 
  这里的话,我们无法准确的给出一个数值,我们要通过性能测试的方式找个一个平衡点!
 
  例如我们写一个服务器程序:服务器通过线程池多线程处理机用户请求!如果要确定线程池的线程数的话,就需要通过对该服务器进行性能分析,构造很多很多请求模拟真实环境,根据这里不同的线程数,来观察处理任务的速度和当个线程的cpu占用率!从而找到一个平衡点!
 
  如果cpu暂用率过高,就无法应对一些突发情况,服务器容易挂!
 
  我们java根据上面的ThreadPoolExecutor类进行封装提供了一个简化版本的线程池!Executors供我们使用!
 
  我们通过Executors的使用学习,实现一个线程池!
 
  Executors
 
  java.util.concurrent.Executors
 
  下面都是Executor类中创建线程池的一些静态方法
 
  创建可以扩容的线程池
 
  创建一个指定容量的线程池
 
  创建单线程池
 
  创建一个线程池含有任务队列
 
  我们重点学习创建指定大小得到线程池方法!
 
  //Executors使用案例
  import java.util.concurrent.ExecutorService;
  import java.util.concurrent.Executors;
  public class Demo3 {
      public static void main(String[] args) {
          //创建一个指定线程个数为10的线程池
          ExecutorService executorService = Executors.newFixedThreadPool(10);
          for (int i = 0; i < 100; i++) {
              int finalI = i;
              executorService.submit(new Runnable() {
                  @Override
                  public void run() {
                      System.out.println("hello executor!"+ finalI);
                  }
              });
          }
      }
  }
 
  我们通过ExecutorService类中的submit可以将多个任务注册到线程池中,然后线程池中的线程将任务并发执行,大大提升了编程效率!可以看到,啪的一下线程池linux,100个任务给10个线程一下就执行结束了!
 
  实现线程池
 
  我们还是分析一下线程池用什么功能,里面都有些啥!
 
  //模拟实现线程池
  class ThreadPool {
      //描述任务 直接使用Runnable
      //组织任务
      private BlockingQueue<Runnable> queue = new LinkedBlockingDeque<>();
      //描述工作线程
      static class Worker extends Thread {//继承Thread类
          BlockingQueue<Runnable> queue = null;
          @Override
          public void run() {
              while (true){
                  try {
                      //拿到任务
                      Runnable runnable = queue.take();
                      //执行任务
                      runnable.run();
                  } catch (InterruptedException e) {
                      e.printStackTrace();
 
                  }
              }
          }
          //通过构造方法拿到外面的任务队列!
          public Worker(BlockingQueue<Runnable> queue) {
              this.queue = queue;
          }
      }
      //组织多个工作线程
      //将多个工作线程放入到workers中!
      public List<Thread>workers = new LinkedList<>();
      public ThreadPool(int n) {//指定放入线程数量
          for (int i = 0; i < n; i++) {//创建多个工作线程
              Worker worker = new Worker(queue);
              worker.start();//启动工作线程
              workers.add(worker);//放入线程池
          }
      }
      //创建一个方法供我们放入任务
      public void submit(Runnable runnable){
          try {
              queue.put(runnable);
          } catch (InterruptedException e) {
              e.printStackTrace();
          }
      }
  }
  //测试代码
  public class demo5 {
      public static void main(String[] args) {
          //线程池线程数量10
          ThreadPool pool = new ThreadPool(10);
          for (int i = 0; i <100 ; i++) {//100个任务
              int finalI = i;
              pool.submit(new Runnable() {
                  @Override
                  public void run() {
                      System.out.println("hello ThreadPool "+ finalI);
                  }
              });
          }
      }
  }
  运行效果
 
  案例总结 MyTask类描述一个任务 Runnable + time 带有优先级的阻塞队列 扫描线程,不停从队首取出元素,检测时间是否到达,并且执行任务,使用wait解决忙等位问题! 实现schedule方法 描述一个任务Runnable 组织任务,带有优先级的阻塞队列 创建一个工作线程work类,从任务队列获取任务,执行任务 组织工作线程works数据结构存放work 实现一个submit方法将任务放入任务队列中!
 

(编辑:我爱制作网_沈阳站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!