代码拉取完成,页面将自动刷新
同步操作将从 帝八哥/JavaBooks 强制同步,此操作会覆盖自 Fork 仓库以来所做的任何修改,且无法恢复!!!
确定后同步将在后台操作,完成时将刷新页面,请耐心等待。
面试必问高频
面试官:了解线程池嘛?
我:了解
面试官:为啥子采用线程池?有啥子优点?
我:我大概分为3点
面试官:都了解哪些线程池?
我:我暂时知道的一些的如:newFixedThreadPool(固定线程池)、newSingleThreadExecutor(单个线程的线程池)、newCachedThreadPool(缓存线程的线程池)、newScheduledThreadPool(带定时器的线程池),还有几个就不说了。
我就举点源码吧
newFixedThreadPool:
// core和max是一样的
// blockQueue是无界阻塞队列
// 嗯, 不好不好!!!
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
newSingleThreadExecutor
// core和max无非都是1而已
// blockQueue是无界阻塞队列
// 嗯, 不好不好!!!
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
newCachedThreadPool
// core 0
// max有点狠,不怕暴栈?
// 队列还是SynchronousQueue,还真怕
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
面试官:讲一下线程池的参数?
我:没问题,ThreadPoolExecutor源码走起:
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
面试官:讲一下都有哪些拒绝策略
我:还好我提前准备
RejectedExecutionException
来拒绝新任务的处理。面试官:线程池的线程数量怎么确定
我:分情况,一般来说...
面试官:shutdown和shutdownNow的区别
我:上源码:
// 等待所有线程执行任务完毕之后退出
public void shutdown() {
final ReentrantLock mainLock = this.mainLock;
// 获取锁
mainLock.lock();
try {
// 检查
checkShutdownAccess();
// 设置状态
advanceRunState(SHUTDOWN);
interruptIdleWorkers();
onShutdown(); // hook for ScheduledThreadPoolExecutor
} finally {
mainLock.unlock();
}
// 主要在于这里,根据状态来是否立马停止还是等线程执行完毕过后停止
tryTerminate(); // 这里就不贴了
}
// 和上面的差不多,立马中断所有线程,关闭线程池
public List<Runnable> shutdownNow() {
List<Runnable> tasks;
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
checkShutdownAccess();
// 设置状态
advanceRunState(STOP);
interruptWorkers();
tasks = drainQueue();
} finally {
mainLock.unlock();
}
tryTerminate();
return tasks;
}
面试官:execute和submit的区别
我:心累
// execute
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
/*
* Proceed in 3 steps:
*
* 1. If fewer than corePoolSize threads are running, try to
* start a new thread with the given command as its first
* task. The call to addWorker atomically checks runState and
* workerCount, and so prevents false alarms that would add
* threads when it shouldn't, by returning false.
*
* 2. If a task can be successfully queued, then we still need
* to double-check whether we should have added a thread
* (because existing ones died since last checking) or that
* the pool shut down since entry into this method. So we
* recheck state and if necessary roll back the enqueuing if
* stopped, or start a new thread if there are none.
*
* 3. If we cannot queue task, then we try to add a new
* thread. If it fails, we know we are shut down or saturated
* and so reject the task.
*/
// 按还是翻译了一下:
// 1.如果正在运行的线程少于corePoolSize线程,请尝试使用给定命令作为其第一个任务来启动新线程。
// 对addWorker的调用从原子上检查runState和workerCount,从而通过返回false来防止在不应该添加线程的情况下发出虚假警报。
// 2.如果一个任务可以成功排队,那么我们仍然需要仔细检查是否应该添加一个线程(因为现有线程自上次检查后就死掉了)或该池自进入该方法后就关闭了。
// 因此,我们重新检查状态,并在必要时回滚排队(如果已停止),或者在没有线程时启动一个新线程。
// 3.如果我们无法将任务排队,则尝试添加一个新线程。
// 如果失败,我们知道我们已关闭或已饱和,因此拒绝该任务。
// 总结:说白了,就是上面的流程图
int c = ctl.get();
if (workerCountOf(c) < corePoolSize) {
if (addWorker(command, true))
return;
c = ctl.get();
}
if (isRunning(c) && workQueue.offer(command)) {
int recheck = ctl.get();
if (! isRunning(recheck) && remove(command))
reject(command);
else if (workerCountOf(recheck) == 0)
addWorker(null, false);
}
else if (!addWorker(command, false))
reject(command);
}
//不过传递的参数,Runnable,那么就意味着没有返回值
// 简单看一下submit吧。
// 不必多说了
<T> Future<T> submit(Callable<T> task);
Future<?> submit(Runnable task);
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。