1.创建线程有哪几种方法?
- 继承Thread类
- 实现Runnable接口
- 使用Callable类和future类创建
- 使用线程池如executor框架
2.为什么要用线程池?
答:线程的创建和销毁本质上是对系统资源的调用,频繁的操作会浪费大量性能,而使用线程池可以降低系统资源消耗。
3.线程池创建的方法有哪些?
- 使用Executors工厂创建
- 使用newThreadPoolExcutor()创建
4.Excutors工厂封装了哪几种常用线程?
- FixedThreadPool。 固定容量线程池,核心线程数就是最大线程数,超出的任务会在队列里面排队等,使用LinkedBlockingQueue无界队列。
- SingleThreadExecutor。 单线程线程池,任务会一个一个执行,超出的任务会在队列里面排队等待,使用LinkedBlockingQueue无界队列。
- ScheduledThreadPool。定时线程池,普通线程数量为Integer.MAX_VALUE,核心线程数量固定,使用DelayedWorkQueue延时队列。
- CachedThreadPool。缓存线程池,普通线程数量为Integer.MAX_VALUE,线程闲置60秒就删除,使用SynchronousQueue同步队列。
5.线程池有哪几种任务队列?
- SynchronousQueue 同步队列。这是一个内部没有任何容量的阻塞队列,任何一次插入操作的元素都要等待相对的删除/读取操作,否则进行插入操作的线程就要一直等待,反之亦然。
- LinkedBlockingQueue 无界队列(严格来说并非无界,上限是Integer.MAX_VALUE),基于链表结构。使用无界队列后,当核心线程都繁忙时,后续任务可以无限加入队列,因此线程池中线程数不会超过核心线程数。这种队列可以提高线程池吞吐量,但代价是牺牲内存空间,甚至会导致内存溢出。另外,使用它时可以指定容量,这样它也就是一种有界队列了。
- ArrayBlockingQueue 有界队列,基于数组实现。在线程池初始化时,指定队列的容量,后续无法再调整。这种有界队列有利于防止资源耗尽,但可能更难调整和控制。
- PriorityBlockingQueue 支持优先级排序的无界阻塞队列。存放在PriorityBlockingQueue中的元素必须实现Comparable接口,这样才能通过实现compareTo()方法进行排序。优先级最高的元素将始终排在队列的头部;PriorityBlockingQueue不会保证优先级一样的元素的排序,也不保证当前队列中除了优先级最高的元素以外的元素,随时处于正确排序的位置。
- DelayQueue 延迟队列。基于二叉堆实现,同时具备:无界队列、阻塞队列、优先队列的特征。DelayQueue延迟队列中存放的对象,必须是实现Delayed接口的类对象。通过执行时延从队列中提取任务,时间没到任务取不出来。更多内容请见DelayQueue。
- LinkedBlockingDeque 双端队列。基于链表实现,既可以从尾部插入/取出元素,还可以从头部插入元素/取出元素。
- LinkedTransferQueue 由链表结构组成的无界阻塞队列。这个队列比较特别的时,采用一种预占模式,意思就是消费者线程取元素时,如果队列不为空,则直接取走数据,若队列为空,那就生成一个节点(节点元素为null)入队,然后消费者线程被等待在这个节点上,后面生产者线程入队时发现有一个元素为null的节点,生产者线程就不入队了,直接就将元素填充到该节点,并唤醒该节点等待的线程,被唤醒的消费者线程取走元素。
6.线程池有哪几种拒绝策略?
- AbortPolicy (默认) 丢弃任务并抛出异常。
- CallerRunsPolicy 直接运行这个任务的run方法,但并非是由线程池的线程处理,而是交由任务的调用线程处理。
- DiscardPolicy 直接丢弃任务,不抛出任何异常。
- DiscardOldestPolicy 将当前处于等待队列列头的等待任务强行取出,然后再试图将当前被拒绝的任务提交到线程池执行。
7.线程池(线程)有哪几种状态?
- new 新创建
- runnable 就绪
- running 运行中
- blocked 阻塞
- dead 死亡