一、线程池中executor()与submit()区别?

1.executor无返回值、submit有返回值
image.png

二、线程池如何在没有任务时保持线程存活?如何对多余线程销毁?

  1. 线程池中线程都对应一个Worker对象,启动Worker对象关联的线程(调用start方法)。触发worker执行runWoker方法,runWorker方法会通过getTask,从阻塞队列中获取任务。<br />当workerCount <= corePoolSize 时<br /> getTask方法获取任务时,使用take方法(不会超时),进行当前核心线程的阻塞,直到新的任务添加到队列中。使用这种方式保证核心线程的存活。<br />当workerCount > corePoolSize 时,且队列中午任务<br /> getTask方法,使用poll(线程池初始化时,设置的时间),如果超时,返回null,跳出runworker方法内的循环,执行线程销毁方法。

三、线程池处理任务的流程

image.png
1.线程池中线程数量小于核心线程数,当提交一个任务时,线程池创建新线程执行任务,直到当前线程数等于corePoolSize;
2.如果当前线程数为corePoolSize,继续提交的任务被保存到阻塞队列中,等待被执行;
3.如果当前阻塞队列满了,且继续提交任务,(如果小于最大线程数)则继续创建新线程执行任务。

四、触发拒绝策略后,原有的任务,是否可以继续?

可以继续执行,调用线程,调用拒绝方法。执行拒绝逻辑。
执行的任务发生异常?
当添加到线程池中的任务执行异常时,线程池会将执行的线程移除。并重新添加一个工作线程,继续执行后续任务

五、线程数量设置

  1. cpu密集型:cup核数+1<br /> IO密集型:2*cup核数+1<br /> 最佳线程数:cup核数*[1+(IO耗时/CPU耗时)]

六、cas是否涉及内核态(kernel Mode)和用户态(User Mode)切换?

不涉及。因为只是对比jvm内存中的中的数据
应用程序一般会在以下几种情况下切换到内核模式:
1. 系统调用。
2. 异常事件。当发生某些预先不可知的异常时,就会切换到内核态,以执行相关的异常事件。
3. 设备中断。在使用外围设备时,如外围设备完成了用户请求,就会向CPU发送一个中断信号,则CPU暂停执行原本的下一条指令,转去处理中断事件。此时,如果原来在用户态,则自然就会切换到内核态。

七、如何优雅停止线程

Java没有提供一种安全、直接的方法来停止某个线程,而是提供了中断机制。
中断机制是一种协作机制,设置中断标志并不能直接终止另一个线程,而需要被中断的线程(根据标志位)自己处理。被中断的线程拥有完全的自主权,它既可以选择立即停止,也可以选择一段时间后停止,也可以选择不停止

八、为什么说创建java线程的方式本质上只有一种。

九、java线程之间如何通信,有哪些方式

十、Timer执行定时任务的比较,相比Timer,ScheduedThreadPoolExecutor有什么优点。

  • ScheduledThreadPoolExecutor继承自ThreadPoolExecutor,也是一个线程池,也有coorPoolSize和workQueue,ScheduledThreadPoolExecutor特殊的地方在于,自己实现了优先工作队列DelayedWorkQueue;
  • ScheduedThreadPoolExecutor实现了ScheduledExecutorService,所以就有了任务调度的方法,如schedule,scheduleAtFixedRate和scheduleWithFixedDelay。
  • 内部类ScheduledFutureTask继承FutureTask,实现了任务的异步执行并且可以获取返回结果。同时也实现了Delayed接口,可以通过getDelay方法获取将要执行的时间间隔;
  • 周期任务的执行其实是调用了FutureTask类中的runAndReset方法,每次执行完不设置结果和状态。
  • 详细分析了DelayedWorkQueue的数据结构,它是一个基于最小堆结构的优先队列,并且每次出队时能够保证取出的任务是当前队列中下次执行时间最小的任务。同时注意一下优先队列中堆的顺序,堆中的顺序并不是绝对的,但要保证子节点的值要比父节点的值要大,这样就不会影响出队的顺序。

Timer是本质是单线程执行