侧边栏

基础(一)

基础(一)

1、如何自定义线程池?创建线程池是会有哪些影响因素或者说涉及哪些参数?创建线程的执行流程?

  1.通过Executors创建【不推荐,内存溢出】
    a.ExecutorService pool = Executors.newSingleThreadExecutor();单线程化的线程池,只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO,LIFO,优先级)执行,可执行的队列数:Integer.MAX_VALUE
    b.ExecutorService pool = Executors.newFixedThreadPool(int);创建一个定长的线程池,支持定时及周期性任务执行;
    c.ExecutorService pool = Executors.newCacheThreadPool();创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程;
    d.ScheduledExecutorService pool = Executors.newScheduledThreadPool(int);创建一个线程池,在给定延迟后运行命令或者定期执行,其中ScheduledExecutorService是接口;
    上述四种方法本质都使用Executor类来实现的;

  2.通过ThreadPoolExecutor创建【推荐,线程池的管控,实际开发过程中使用该方式】

private RejectedExecutionHandler handler = new CallerRunsPolicy();
BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<Runnable>(initQueueSize);
ExecutorService boundedThreadPool = new ThreadPoolExecutor(corePoolSize, maximumPoolSize , keepAliveTime, TimeUnit.SECONDS,workQueue, handler);

 

    corePoolSize:核心线程数,包括空闲线程;

    maximumPoolSize:线程池允许的最大线程数;

    keepAliveTime:线程数大于核心数时,终止前多余的空闲线程等待新任务的最长时间;

    TimeUnit.SECONDS:keepAliveTime参数的时间单位;

    workQueue:执行前保持任务的队列,此队列仅由保持execute方法提交的Runnable任务;

    handler:由于超出线程范围和队列容量而被阻塞时所使用的处理程序;

    api查阅:https://tool.oschina.net/apidocs/apidoc?api=jdk-zh

  3.ThreadPoolExecutor创建的线程执行流程

    • 当一个任务进入时,若核心线程数corePoolSize未满时,则新建一个核心线程执行;
    • 若核心线程数满了,但是阻塞队列没有满,则将该线程先放入阻塞队列中;
    • 如果核心线程数和阻塞队列都满了,但是未达到最大线程数maximumPoolSize时,会新建一个非核心线程执行任务
    • 如果核心线程数,阻塞队列,最大线程数都满了,就会执行线程池的拒绝策略
      • AbortPolicy:默认策略,丢弃任务并抛出RejectedExecutionException运行时异常;
      • CallerRunsPolicy:提交任务的线程执行该任务,并通过反馈机制,减慢提交新任务的速度;
      • DiscardPolicy:直接丢弃新提交的任务;
      • DiscardOldestPolicy:如果执行器没有关闭,队列头的任务将被丢弃,然后执行器重新尝试执行任务,如果失败,则重复这一过程;

2、String可以被继承么?为什么?

  public final class String implements Serializable, Comparable<String>, CharSequence {}
  不可以被继承,被final修饰的类无法被继承

3、HashMap的底层结构介绍一下?

  1、HashMap的数据结构:数据+(链表或红黑树),因为数组的特点查询快、增删慢,链表的特点相反。在HashMap底层的结构完美解决数组和链表的问题,使查询、增删都很快。
  2、HashMap存储元素过程:map.put("key","value");
    a、计算出“key”的hashcode,Object类中有本地方法public native int hashCode();调用该方法会生成一个int的整数,称作hash码。

   哈希码和调用它的对象地址和内容有关。对于同一个对象(使用equals比较返回true),那么无论何时哈希值是相同的,对于两个对象如果他们的equals返回false,那么他们的哈希值也有可能相等。

    b、根据key的哈希值对HashMap的容量取模,得到元素存储的数组下标。如果下标位置为空,直接放进去,如果不为空,则需要通过equals比较该位置的元素值是否和待插入元素是否相等,相等的话直接覆盖,不相等在该元素下使用链表存储结构存储该元素。每个元素节点都有一个next属性指向下一个节点,这里由数组变成了数组+链表结构。因为链表中元素太多会影响查询效率,所以元素达到8个时使用链表存储转变成使用红黑树存储,原因是红黑树是平衡二叉树,在查找性能方面比链表要高。
    c、HashMap中有两个重要参数:初始容量和加载因子,初始容量是创建HashMap时数组分配的容量大小,默认16,数组容量大小乘加载因子得到一个值,一旦数组中存储的元素超过该值就会调用rehash方法将数组容量增加到原来两倍,也称为扩容。在做扩容的时候会生成一个新的数组,原来的所有数据需要重新计算哈希值重新分配到新的数组,所以扩容操作非常消耗性能,所以在定义HashMap时,如果知道其容量大小最好先定义好长度,避免扩容引发性能消耗。

4、谈谈对ThreadLocal的理解,以及使用场景?

  ThreadLocal提供线程的局部变量,使线程拥有自己的局部变量,当使用ThreadLocal维护变量,会为每个使用该变量的线程提供独立的变量副本,所以每个线程都可以独立改变自己的副本,而不会影响其他线程所对应的副本。

posted @ 2022-02-18 23:35  泡代码的小二黑  阅读(27)  评论(0编辑  收藏  举报
script src="https://files.cnblogs.com/files/fenggwsx/clipboard.min.js"/script script src="https://files.cnblogs.com/files/fenggwsx/cp.js"/script