薦閱讀:
線程池是我們經(jīng)常使用的工具,也是面試必問的知識點,那么如何優(yōu)雅的關閉線程池那?
線程池相信大家都使用過,但是使用完成之后如何關閉線程池大家真的未必真的會使用。有人可能會說調(diào)用shutdown或者shutdownNow就可以了,真的有那么簡單嗎?如果你關閉線程池的姿勢不正確,最嚴重的情況會導致線程一直存在系統(tǒng)中。
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(事件循環(huán))是 JavaScript 運行時環(huán)境(如瀏覽器和 Node.js)的核心機制之一,它使得 JavaScript 能夠處理異步操作而不會阻塞程序的執(zhí)行。了解 Event Loop 對于理解 JavaScript 的非阻塞行為和編寫高效的異步代碼至關重要。
首先,重要的是要理解 JavaScript 是一種單線程的語言。這意味著 JavaScript 在同一時間內(nèi)只能執(zhí)行一個任務。然而,JavaScript 需要能夠處理各種異步操作(如 AJAX 請求、文件讀取、用戶交互等),這些操作可能會花費很長時間完成。為了解決這個問題,JavaScript 采用了 Event Loop 和 Callback Queues(回調(diào)隊列)。
調(diào)用棧是 JavaScript 代碼執(zhí)行時的數(shù)據(jù)結(jié)構(gòu),用于存儲函數(shù)調(diào)用和返回地址。每當一個函數(shù)被調(diào)用時,它就會被推入調(diào)用棧,并在函數(shù)執(zhí)行完畢后從棧中彈出。如果調(diào)用棧滿了(即達到了最大調(diào)用深度),則會發(fā)生棧溢出錯誤。
堆是用于存儲對象、數(shù)組等引用類型的內(nèi)存區(qū)域。與調(diào)用棧不同,堆是動態(tài)分配的,并且其大小不是固定的。
Web APIs 是瀏覽器提供的一組與瀏覽器功能交互的接口,如 DOM 操作、網(wǎng)絡請求等。這些 API 通常是異步的,并且它們有自己的線程或進程來處理請求。
當異步操作完成時(如 AJAX 請求、setTimeout、Promise 解決等),相應的回調(diào)函數(shù)會被放入任務隊列(或稱為宏任務隊列)或微任務隊列中。任務隊列中的任務在當前的執(zhí)行棧清空后才會被執(zhí)行,而微任務隊列中的任務會在當前執(zhí)行棧清空后、但下一個宏任務執(zhí)行前立即執(zhí)行。
Event Loop 的工作流程可以概括為以下幾個步驟:
console.log('1');
setTimeout(()=> {
console.log('setTimeout 宏任務隊列');
}, 0);
new Promise((resolve)=> {
console.log('Promise 立即執(zhí)行');
resolve();
}).then(()=> {
console.log('then 微任務隊列');
});
console.log('2');
//輸出順序
1
Promise 立即執(zhí)行
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 立即執(zhí)行1');
resolve();
}).then(()=> {
console.log('then 微任務隊列1');
new Promise((resolve)=> {
console.log('Promise 立即執(zhí)行2');
resolve();
}).then(()=> {
console.log('then 微任務隊列2');
});
});
console.log('2');
//輸出順序
1
Promise 立即執(zhí)行1
2
then 微任務隊列1
Promise 立即執(zhí)行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 立即執(zhí)行');
resolve();
}).then(()=> {
console.log('then 微任務隊列');
});
console.log('2');
//輸出順序
1
async1 1
async2
promise 立即執(zhí)行
2
async1 2
then 微任務隊列
setTimeout 宏任務隊列
解釋:
Event Loop 是 JavaScript 異步編程的基石,它使得 JavaScript 能夠在不阻塞主線程的情況下處理各種異步操作。通過理解 Event Loop 的工作原理,我們可以更加高效地編寫異步代碼,避免潛在的錯誤和性能問題。
一步:解析 HTML
第二步:樣式計算
第四步:分層
第五步:繪制
第六步:分塊
第七步:光柵化
第八步:
*請認真填寫需求信息,我們會在24小時內(nèi)與您取得聯(lián)系。