1. UUID 128位占用空间较多
    2. (重要)UUID是无序的在插入数据时会造成索引重排,如果是有序的主键直接在B+树的最后插入数据即可

线程池相关知识点

java 骐骏 2年前 (2019-05-18) 1300次浏览 已收录 0个评论 扫描二维码
  1.  从阻塞队列开始说起
    1. 在操作阻塞队列时,如果队列内容为空,那么消费线程会被阻塞;如果队列已经满了,那么生产线程将会阻塞
    2. 阻塞队列的分类
      1. ArrayBlockingQueue
        1. 有界队列
        2. 底层为Array形式存储
        3. 如果所有的任务都是按顺序执行,不存在“插队”和从队伍中离开,则适合使用ArrayBlockingQueue
      2. LinkedBlockingQueue
        1. 无界队列
        2. 底层为链表形式存储
        3. 如果存在“插队”,和从队伍中离开的情况则适合使用LinkedBlockingQueue
      3. SynchronousQueue
        1. 只能有一个元素
    3. 阻塞队列的使用示例略
  2. 使用线程的优势
    1. 减少了线程创建,销毁的性能消耗,复用了线程
    2. 充分利用cpu的内核(相对于单线程),省略了上下文的切换
    3. 提高了线程的可管理性,线程池可以对线程统一分配,调优和监控
    4. 由于减少了线程的创建时间,所以响应速度会有所提高
  3. 线程池的几个参数作用
    public ThreadPoolExecutor(int corePoolSize,
                                  int maximumPoolSize,
                                  long keepAliveTime,
                                  TimeUnit unit,
                                  BlockingQueue<Runnable> workQueue,
                                  ThreadFactory threadFactory,
                                  RejectedExecutionHandler handler)
    
    1. corePoolSize:线程池的核心线程数量,如果线程池中的线程数量小于这个数,每次执行execute()方法会创建新的线程;如果正在运行的线程数大于corePoolSize,当有新的任务时候,会将任务加入到阻塞队列
    2. 当任务已经填满阻塞对列,则会创建新的线程去执行任务,直到线程数到达maximumPoolSize;maximumPoolSize就是线程池中可以创建的最大线程数;如果线程池中的线程已经超过corePoolSize,当队列中的任务逐渐减少时,线程池的中的线程也会销毁。
    3. 当线程超过keepAliveTime没有执行任务时,线程池中的线程就会销毁,直到线程数量减少到 corePoolSize;如果设置了allowCoreThreadTimeOut,核心线程也会销毁,线程池中线程数量会减少到0
    4. unit参数就是线程超时销毁的时间单位,如TimeUnit.MILLISECONDS
    5. workQueue就是暂存任务的阻塞队列
    6. threadFactory是创建线程的工厂类,一般使用默认的工厂类,Executors.defaultThreadFactory()
    7. handler 线程池的拒绝策略
      1. 在线程池中线程的数量已经达到maximumPoolSize,并且阻塞对列中已经放满了待执行的任务,那么线程池就会执行拒绝策略,拒绝新的任务
      2. 常见的拒绝策略
        1. new ThreadPoolExecutor.CallerRunsPolicy()
          1. 将新的任务交给调用者执行
        2. new ThreadPoolExecutor.AbortPolicy()
          1. 直接抛出RejectedExecutionException异常
        3. new ThreadPoolExecutor.DiscardPolicy()
          1. 丢弃调新的任务,但不抛出异常
        4. new ThreadPoolExecutor.DiscardOldestPolicy()
          1. 丢弃队列中最老的任务,但不抛出异常
  4. Executors提供的几个线程池就像Collectionss提供针对Collection的工具一样,Executors提供了针对Executor的各种工具方法,其中最常见的便是·创建线程的工具方法,有四种:
    //创建n个线程,n为Integer.MAX_VALUE
    Executors.newCachedThreadPool();
    //有固定线程数的线程池,corePoolSize和maxPoolSize相等
    Executors.newFixedThreadPool(10);
    //有定时或周期执行的线程池
    Executors.newScheduledThreadPool(10);
    //只有一个线程的线程池 corePoolSize = maxPoolSize = 1
    Executors.newSingleThreadExecutor();
    

    特别注意:在生产项目中一般不使用Executors提供的这几个线程池,因为它底层的阻塞队列是无限的,有可能会造成OOM

  5. 带返回值的线程池
    1. 如果要获取子线程返回的结果,那么要实现Callable接口
    2. FutureTask类实现了Runnable接口,并且拥有包含Callable参数的构造函数FutureTask(Callable task),可以通过futureTask去执行要获得返回结果的子线程
    3. 一个执行实现Callable接口的示例
      public class ThreadPoolDemo {
      
      
          public static  void main(String[] args){
      
                TaskWithReturn taskWithReturn = new TaskWithReturn();
              FutureTask<Integer> taskWithReturnFutureTask = new FutureTask<Integer>(taskWithReturn);
              Thread thread = new Thread(taskWithReturnFutureTask);
              thread.start();
          }
      
          private static class TaskWithReturn implements Callable<Integer> {
              @Override
              public Integer call() throws Exception {
                  System.out.println(Thread.currentThread().getName());
                  return 1234;
              }
          }
      }
      
  6. ThreadPoolExecutor的execute方法和submit方法区别
    1. execute只能执行实现了Runnable接口的类;submit可以执行实现了Runnable接口的类也可以执行实现了Callable接口的类
    2. submit方法可以通过返回值Future获取到子线程的执行结果和异常信息, 如果线程正确执行完毕future.get()获取到线程的返回结果,如果子线程抛出异常future.get()获取到异常信息

 

二、 线程池解决的什么问题

线程池解决的核心问题就是资源管理问题。在并发环境下,系统不能够确定在任意时刻中,有多少任务需要执行,有多少资源需要投入。这种不确定性将带来以下若干问题:

  1. 频繁申请/销毁资源和调度资源,将带来额外的消耗,可能会非常巨大。
  2. 对资源无限申请缺少抑制手段,易引发系统资源耗尽的风险。
  3. 系统无法合理管理内部的资源分布,会降低系统的稳定性。

原创不易,转载请注明原文链接:线程池相关知识点
喜欢 (1)
[]
分享 (0)
发表我的评论
取消评论

表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址