荐阅读:
线程池是我们经常使用的工具,也是面试必问的知识点,那么如何优雅的关闭线程池那?
线程池相信大家都使用过,但是使用完成之后如何关闭线程池大家真的未必真的会使用。有人可能会说调用shutdown或者shutdownNow就可以了,真的有那么简单吗?如果你关闭线程池的姿势不正确,最严重的情况会导致线程一直存在系统中。
public class ExecutorUtil {
private static final Logger logger=LoggerFactory.getLogger(ExecutorUtil.class);
private static final ThreadPoolExecutor shutdownExecutor=new ThreadPoolExecutor(0, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(100),
new NamedThreadFactory("Close-ExecutorService-Timer", true));
public static boolean isTerminated(Executor executor) {
if (executor instanceof ExecutorService) {
if (((ExecutorService) executor).isTerminated()) {
return true;
}
}
return false;
}
/**
* Use the shutdown pattern from:
* https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ExecutorService.html
* @param executor the Executor to shutdown
* @param timeout the timeout in milliseconds before termination
*/
public static void gracefulShutdown(Executor executor, int timeout) {
if (!(executor instanceof ExecutorService) || isTerminated(executor)) {
return;
}
final ExecutorService es=(ExecutorService) executor;
try {
// Disable new tasks from being submitted
es.shutdown();
} catch (SecurityException ex2) {
return;
} catch (NullPointerException ex2) {
return;
}
try {
// Wait a while for existing tasks to terminate
if (!es.awaitTermination(timeout, TimeUnit.MILLISECONDS)) {
es.shutdownNow();
}
} catch (InterruptedException ex) {
es.shutdownNow();
Thread.currentThread().interrupt();
}
if (!isTerminated(es)) {
newThreadToCloseExecutor(es);
}
}
public static void shutdownNow(Executor executor, final int timeout) {
if (!(executor instanceof ExecutorService) || isTerminated(executor)) {
return;
}
final ExecutorService es=(ExecutorService) executor;
try {
es.shutdownNow();
} catch (SecurityException ex2) {
return;
} catch (NullPointerException ex2) {
return;
}
try {
es.awaitTermination(timeout, TimeUnit.MILLISECONDS);
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
}
if (!isTerminated(es)) {
newThreadToCloseExecutor(es);
}
}
private static void newThreadToCloseExecutor(final ExecutorService es) {
if (!isTerminated(es)) {
shutdownExecutor.execute(new Runnable() {
@Override
public void run() {
try {
for (int i=0; i < 1000; i++) {
es.shutdownNow();
if (es.awaitTermination(10, TimeUnit.MILLISECONDS)) {
break;
}
}
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
} catch (Throwable e) {
logger.warn(e.getMessage(), e);
}
}
});
}
}
}
作者:克里斯朵夫李维
链接:https://juejin.im/post/5e9ec57df265da47c9171456
avaScript 的 Event Loop(事件循环)是 JavaScript 运行时环境(如浏览器和 Node.js)的核心机制之一,它使得 JavaScript 能够处理异步操作而不会阻塞程序的执行。了解 Event Loop 对于理解 JavaScript 的非阻塞行为和编写高效的异步代码至关重要。
首先,重要的是要理解 JavaScript 是一种单线程的语言。这意味着 JavaScript 在同一时间内只能执行一个任务。然而,JavaScript 需要能够处理各种异步操作(如 AJAX 请求、文件读取、用户交互等),这些操作可能会花费很长时间完成。为了解决这个问题,JavaScript 采用了 Event Loop 和 Callback Queues(回调队列)。
调用栈是 JavaScript 代码执行时的数据结构,用于存储函数调用和返回地址。每当一个函数被调用时,它就会被推入调用栈,并在函数执行完毕后从栈中弹出。如果调用栈满了(即达到了最大调用深度),则会发生栈溢出错误。
堆是用于存储对象、数组等引用类型的内存区域。与调用栈不同,堆是动态分配的,并且其大小不是固定的。
Web APIs 是浏览器提供的一组与浏览器功能交互的接口,如 DOM 操作、网络请求等。这些 API 通常是异步的,并且它们有自己的线程或进程来处理请求。
当异步操作完成时(如 AJAX 请求、setTimeout、Promise 解决等),相应的回调函数会被放入任务队列(或称为宏任务队列)或微任务队列中。任务队列中的任务在当前的执行栈清空后才会被执行,而微任务队列中的任务会在当前执行栈清空后、但下一个宏任务执行前立即执行。
Event Loop 的工作流程可以概括为以下几个步骤:
console.log('1');
setTimeout(()=> {
console.log('setTimeout 宏任务队列');
}, 0);
new Promise((resolve)=> {
console.log('Promise 立即执行');
resolve();
}).then(()=> {
console.log('then 微任务队列');
});
console.log('2');
//输出顺序
1
Promise 立即执行
2
then 微任务队列
setTimeout 宏任务队列
解释:
console.log('1');
setTimeout(()=> {
console.log('setTimeout 宏任务队列1');
new Promise((resolve)=> {
console.log('Promise in setTimeout');
resolve();
}).then(()=> {
console.log('then in setTimeout');
});
setTimeout(()=> {
console.log('setTimeout 宏任务队列2');
}, 0);
}, 0);
new Promise((resolve)=> {
console.log('Promise 立即执行1');
resolve();
}).then(()=> {
console.log('then 微任务队列1');
new Promise((resolve)=> {
console.log('Promise 立即执行2');
resolve();
}).then(()=> {
console.log('then 微任务队列2');
});
});
console.log('2');
//输出顺序
1
Promise 立即执行1
2
then 微任务队列1
Promise 立即执行2
then 微任务队列2
setTimeout 宏任务队列1
Promise in setTimeout
then in setTimeout
setTimeout 宏任务队列2
解释:
const async1=async ()=> {
console.log('async1 1');
await async2();
console.log('async1 2');
}
const async2=async ()=> {
console.log('async2');
}
console.log('1');
setTimeout(()=> {
console.log('setTimeout 宏任务队列');
}, 0);
async1();
new Promise((resolve)=> {
console.log('promise 立即执行');
resolve();
}).then(()=> {
console.log('then 微任务队列');
});
console.log('2');
//输出顺序
1
async1 1
async2
promise 立即执行
2
async1 2
then 微任务队列
setTimeout 宏任务队列
解释:
Event Loop 是 JavaScript 异步编程的基石,它使得 JavaScript 能够在不阻塞主线程的情况下处理各种异步操作。通过理解 Event Loop 的工作原理,我们可以更加高效地编写异步代码,避免潜在的错误和性能问题。
一步:解析 HTML
第二步:样式计算
第四步:分层
第五步:绘制
第六步:分块
第七步:光栅化
第八步:
*请认真填写需求信息,我们会在24小时内与您取得联系。