Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 日本亚洲黄色,中文字幕激情视频,日本!日本!在线播放

          整合營銷服務(wù)商

          電腦端+手機端+微信端=數(shù)據(jù)同步管理

          免費咨詢熱線:

          超實用!學(xué)習(xí)dubbo如何優(yōu)雅關(guān)閉線程池

          超實用!學(xué)習(xí)dubbo如何優(yōu)雅關(guān)閉線程池

          薦閱讀:

          • 騰訊T4大佬總結(jié):微服務(wù)、SpringBoot、SpringCloud、Dubbo文檔

          基本方法學(xué)習(xí)

          線程池是我們經(jīng)常使用的工具,也是面試必問的知識點,那么如何優(yōu)雅的關(guān)閉線程池那?

          線程池相信大家都使用過,但是使用完成之后如何關(guān)閉線程池大家真的未必真的會使用。有人可能會說調(diào)用shutdown或者shutdownNow就可以了,真的有那么簡單嗎?如果你關(guān)閉線程池的姿勢不正確,最嚴重的情況會導(dǎo)致線程一直存在系統(tǒng)中。

          • shutDown:通知線程池啟動有序關(guān)閉,執(zhí)行線程池之前已經(jīng)提交的任務(wù),但是不再接受新的任務(wù)。調(diào)用shutDown后再提交任務(wù)將會拋出RejectedExecutionException異常。
          • shutDownNow:嘗試立即停止所有已經(jīng)提交的任務(wù),并會返回正在等待執(zhí)行(未執(zhí)行)的任務(wù)列表。shutDownNow通過向線程池中的線程發(fā)送一個中斷請求而中止線程,如果線程池中運行了會拋出InterruptedException的程序,將會拋出一個InterruptedException。如過這個線程不能響應(yīng)中斷那么可能永遠無法被終止。
          • isTerminated:所有的任務(wù)都被關(guān)閉返回true,否則返回false。只有調(diào)用了shutDown或者shutDownNow,isTerminated才可能為true。
          • awaitTermination(long timeout, TimeUnit unit) throws InterruptedException:阻塞當(dāng)前線程直到 所有任務(wù)執(zhí)行完畢 或者超時 或者當(dāng)前線程被中斷 如果所有任務(wù)都關(guān)閉,則返回true,否則返回false。

          優(yōu)雅關(guān)閉線程池的正確姿勢

          • step1:執(zhí)行shutdown方法,等待所有任務(wù)執(zhí)行完畢并拒絕新任務(wù)的提交。
          • step2:執(zhí)行awaitTermination(long timeout,TimeUnit unit),指定超時時間,判斷是是否已經(jīng)關(guān)閉所有任務(wù),防止線程永遠無法關(guān)閉。
          • step3:如果step2返回fasle,或者被中斷。調(diào)用shutDownNow方法立即關(guān)閉線程池所有任務(wù)。

          dubbo關(guān)閉線程池工具類學(xué)習(xí)

          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 的非阻塞行為和編寫高效的異步代碼至關(guān)重要。

          1. JavaScript 是單線程的

          首先,重要的是要理解 JavaScript 是一種單線程的語言。這意味著 JavaScript 在同一時間內(nèi)只能執(zhí)行一個任務(wù)。然而,JavaScript 需要能夠處理各種異步操作(如 AJAX 請求、文件讀取、用戶交互等),這些操作可能會花費很長時間完成。為了解決這個問題,JavaScript 采用了 Event Loop 和 Callback Queues(回調(diào)隊列)。

          2. 調(diào)用棧(Call Stack)

          調(diào)用棧是 JavaScript 代碼執(zhí)行時的數(shù)據(jù)結(jié)構(gòu),用于存儲函數(shù)調(diào)用和返回地址。每當(dāng)一個函數(shù)被調(diào)用時,它就會被推入調(diào)用棧,并在函數(shù)執(zhí)行完畢后從棧中彈出。如果調(diào)用棧滿了(即達到了最大調(diào)用深度),則會發(fā)生棧溢出錯誤。

          3. 堆(Heap)

          堆是用于存儲對象、數(shù)組等引用類型的內(nèi)存區(qū)域。與調(diào)用棧不同,堆是動態(tài)分配的,并且其大小不是固定的。

          4. Web APIs

          Web APIs 是瀏覽器提供的一組與瀏覽器功能交互的接口,如 DOM 操作、網(wǎng)絡(luò)請求等。這些 API 通常是異步的,并且它們有自己的線程或進程來處理請求。

          5. 任務(wù)隊列(Task Queue)和微任務(wù)隊列(Microtask Queue)

          當(dāng)異步操作完成時(如 AJAX 請求、setTimeout、Promise 解決等),相應(yīng)的回調(diào)函數(shù)會被放入任務(wù)隊列(或稱為宏任務(wù)隊列)或微任務(wù)隊列中。任務(wù)隊列中的任務(wù)在當(dāng)前的執(zhí)行棧清空后才會被執(zhí)行,而微任務(wù)隊列中的任務(wù)會在當(dāng)前執(zhí)行棧清空后、但下一個宏任務(wù)執(zhí)行前立即執(zhí)行。

          6. Event Loop 的工作原理

          Event Loop 的工作流程可以概括為以下幾個步驟:

          1. 檢查調(diào)用棧:如果調(diào)用棧為空,則繼續(xù);如果調(diào)用棧不為空,則等待直到調(diào)用棧為空。
          2. 執(zhí)行微任務(wù)隊列:一旦調(diào)用棧為空,Event Loop 就會查看微任務(wù)隊列是否有任務(wù)。如果有,它會依次執(zhí)行微任務(wù)隊列中的所有任務(wù),然后再回到第一步。
          3. 執(zhí)行宏任務(wù)隊列:在所有微任務(wù)都執(zhí)行完畢后,Event Loop 會從宏任務(wù)隊列中取出一個任務(wù)放入調(diào)用棧執(zhí)行。這個過程會不斷重復(fù)。

          7. 常見的宏任務(wù)和微任務(wù)

          • 宏任務(wù)(Macrotasks):包括 script(整體代碼)、setTimeout、setInterval、setImmediate(Node.js 環(huán)境)、I/O、UI rendering 等。
          • 微任務(wù)(Microtasks):包括 Promise.then、Promise.catch、Promise.finally、MutationObserver、process.nextTick(Node.js 環(huán)境)等。

          實例 1:setTimeout 和 Promise

          console.log('1');  
            
          setTimeout(()=> {  
            console.log('setTimeout 宏任務(wù)隊列');  
          }, 0);  
            
          new Promise((resolve)=> {  
            console.log('Promise 立即執(zhí)行');  
            resolve();  
          }).then(()=> {  
            console.log('then 微任務(wù)隊列');  
          });  
            
          console.log('2');
          
          //輸出順序
          1  
          Promise 立即執(zhí)行 
          2  
          then  微任務(wù)隊列
          setTimeout 宏任務(wù)隊列

          解釋

          1. 首先,執(zhí)行同步代碼,輸出 1。
          2. 然后,setTimeout 被調(diào)用,但因為它是一個宏任務(wù),所以它的回調(diào)函數(shù)被放入宏任務(wù)隊列中等待。
          3. 接下來,new Promise 的構(gòu)造函數(shù)被調(diào)用,立即執(zhí)行并輸出 Promise。resolve() 被調(diào)用,但 .then() 中的回調(diào)函數(shù)是異步的,并且是一個微任務(wù),所以它會被放入微任務(wù)隊列中。
          4. 同步代碼繼續(xù)執(zhí)行,輸出 2。
          5. 當(dāng)所有同步代碼執(zhí)行完畢后,Event Loop 開始處理微任務(wù)隊列。它找到 .then() 的回調(diào)函數(shù)并執(zhí)行,輸出 then。
          6. 最后,當(dāng)微任務(wù)隊列為空時,Event Loop 轉(zhuǎn)到宏任務(wù)隊列,執(zhí)行 setTimeout 的回調(diào)函數(shù),輸出 setTimeout。

          實例 2:多個 Promise 和 setTimeout

          console.log('1');  
            
          setTimeout(()=> {  
            console.log('setTimeout  宏任務(wù)隊列1');  
            new Promise((resolve)=> {  
              console.log('Promise in setTimeout');  
              resolve();  
            }).then(()=> {  
              console.log('then in setTimeout');  
            });  
            setTimeout(()=> {  
              console.log('setTimeout 宏任務(wù)隊列2');  
            }, 0);  
          }, 0);  
            
          new Promise((resolve)=> {  
            console.log('Promise 立即執(zhí)行1');  
            resolve();  
          }).then(()=> {  
            console.log('then 微任務(wù)隊列1');  
            new Promise((resolve)=> {  
              console.log('Promise 立即執(zhí)行2');  
              resolve();  
            }).then(()=> {  
              console.log('then 微任務(wù)隊列2');  
            });  
          });  
            
          console.log('2');
          
          //輸出順序
          1 
          Promise 立即執(zhí)行1  
          2  
          then 微任務(wù)隊列1 
          Promise 立即執(zhí)行2  
          then 微任務(wù)隊列2
          setTimeout  宏任務(wù)隊列1  
          Promise in setTimeout  
          then in setTimeout  
          setTimeout  宏任務(wù)隊列2

          解釋

          1. 同步代碼首先執(zhí)行,輸出 1、Promise 1 和 2。
          2. .then() 中的回調(diào)函數(shù)作為微任務(wù)被加入微任務(wù)隊列。
          3. 第一個 setTimeout 被調(diào)用,它的回調(diào)函數(shù)被加入宏任務(wù)隊列。
          4. 當(dāng)所有同步代碼執(zhí)行完畢后,開始執(zhí)行微任務(wù)隊列中的任務(wù)。首先輸出then 微任務(wù)隊列1,然后執(zhí)行 Promise 立即執(zhí)行2then 微任務(wù)隊列2
          5. 微任務(wù)隊列為空后,執(zhí)行宏任務(wù)隊列中的第一個任務(wù)(即第一個 setTimeout 的回調(diào)函數(shù)),輸出相關(guān)日志。
          6. 第二個 setTimeout 的回調(diào)函數(shù)也被加入宏任務(wù)隊列,并在當(dāng)前宏任務(wù)執(zhí)行完畢后執(zhí)行。

          實例 3:async/await 與 Promise

          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 宏任務(wù)隊列');  
          }, 0);  
            
          async1();  
            
          new Promise((resolve)=> {  
            console.log('promise 立即執(zhí)行');  
            resolve();  
          }).then(()=> {  
            console.log('then 微任務(wù)隊列');  
          });  
            
          console.log('2');
          
          //輸出順序
          1
          async1 1
          async2  
          promise 立即執(zhí)行
          2
          async1 2
          then 微任務(wù)隊列
          setTimeout 宏任務(wù)隊列

          解釋

          1. 同步代碼首先執(zhí)行,輸出1。
          2. async1() 被調(diào)用,輸出async1 1。
          3. await async2() 暫停 async1() 的執(zhí)行,async2() 被調(diào)用并輸出 async2。因為 async2() 沒有返回 Promise 或沒有等待的異步操作,所以 await 后面的代碼在 async2() 執(zhí)行完畢后繼續(xù)執(zhí)行。
          4. 同步代碼首先執(zhí)行,輸出promise 立即執(zhí)行和2。
          5. 之后async2執(zhí)行完畢后,同步代碼輸出async1 2,
          6. 當(dāng)所有同步代碼執(zhí)行完畢后,開始執(zhí)行微任務(wù)隊列中的任務(wù)then 微任務(wù)隊列
          7. 最后執(zhí)行宏任務(wù)隊列,輸出setTimeout 宏任務(wù)隊列

          結(jié)論

          Event Loop 是 JavaScript 異步編程的基石,它使得 JavaScript 能夠在不阻塞主線程的情況下處理各種異步操作。通過理解 Event Loop 的工作原理,我們可以更加高效地編寫異步代碼,避免潛在的錯誤和性能問題。

          一步:解析 HTML

          1. 解析過程中遇到 CSS,解析 CSS;遇到 JS ,執(zhí)行 JS;為了提高效率,瀏覽器在開始解析之前,會啟動一個預(yù)解析線程,率先下載 HTML 中外部的 CSS 文件和外部的 JS 文件;
          2. 如果主線程解析到 link位置時,此時外部的 CSS 文件還沒有下載解析完成,主線程不會等待,繼續(xù)執(zhí)行后續(xù)代碼,因為 CSS 下載和解析工作是在預(yù)解析線程中進行的,這也是CSS不會阻塞 HTML 解析的根本原因
          3. 如果主線程解析到 script 位置時;會停止解析 HTML,而去等待 JS文件下載完畢,并將全部代碼執(zhí)行完成后,才會繼續(xù)解析 HTML;這是因為 JS 代碼在執(zhí)行的過程中有可能會修改當(dāng)前的DOM樹;所以DOM 樹的生成必須停止,這也就是 JS 會阻塞HTML 解析的根本原因;

          第二步:樣式計算

          1. 主線程會遍歷得到的 DOM 樹;依次為每個 DOM 樹的節(jié)點計算出最終樣式;
          2. 在這一過程中,很多相對值會變成絕對值;例如:16進制顏色值會變成rgb顏色值,rem、em、vw會變成px;

          1. 第三步:布局
          2. 布局階段主線程會依次遍歷 DOM 樹的每一個節(jié)點,計算每一個節(jié)點的幾何信息;例如節(jié)點的寬、高、相對包含塊的位置;
          3. 大部分的時候 DOM(元素) 樹和 Layout(布局)樹并非一一對應(yīng);
          4. 例如display:none的節(jié)點是沒有幾何信息的;因此不會產(chǎn)生Layout樹、使用了偽元素的選擇器、雖然DOM樹中不存在這些偽元素節(jié)點,但是它們擁有幾何信息,所以會生成Layout樹、還有匿名行盒、匿名塊盒都會導(dǎo)致DOM樹和Layout樹無法一一對應(yīng);
          5. 內(nèi)容必須在行盒中,盒子的類型有CSS來決定,不由HTML來決定,HTML只提供語義化;

          第四步:分層

          1. 主線程會通過一套復(fù)雜的策略來對整個Layout樹進行分層;
          2. 分層的好處在于將來某一個層改變后,僅會對該層進行后續(xù)處理,不會影響到其它層;從而達到提升效率
          3. 滾動條、堆疊上下文、transform、opacity等樣式都會或多或少的影響分層結(jié)果,也可以通過will-嫦娥屬性來更大程度上影響分層結(jié)果。

          第五步:繪制

          1. 主線程會為每個層單獨產(chǎn)生繪制指令集,用于描述這一層的內(nèi)容如何畫出來;
          2. 繪制完成后,主線程將每個圖層的繪制信息提交給 合成線程,剩余的工作將由合成線程完成。

          第六步:分塊

          1. 合成線程首先對每個圖層進行分塊,將其劃分為更多的小區(qū)域;
          2. 它會從線程池中拿取更多的線程來完成分塊工作;

          第七步:光柵化

          1. 分塊完成后,合成線程將塊信息交給GPU進程,以極高的速度完成光柵化;
          2. GPU 進程會開啟多個線程來完成光柵化,并且優(yōu)先處理靠近視口區(qū)域的塊
          3. 光柵化的結(jié)果就是一塊一塊的位置;

          第八步:

          1. 合成線程拿到層,每個塊的位圖后,生成一個個【指引(quad)】信息;
          2. 指引會標識每個位圖感應(yīng)該畫到屏幕的哪個位置,以及會考慮旋轉(zhuǎn),縮放等變形;
          3. 變形發(fā)生在合成線程,與渲染主線程無關(guān),這就是transform效率高的本質(zhì)原因;
          4. 合成線程會把quad提交給GPU進程,由GPU進程產(chǎn)生系統(tǒng)調(diào)用,提交給GPU硬件,完成最終的屏幕成像。

          主站蜘蛛池模板: 一区二区在线观看视频| 亚洲天堂一区二区三区| 风间由美性色一区二区三区| 精品人妻一区二区三区毛片| 丰满人妻一区二区三区视频53| 中文字幕一区二区三区乱码| 亚洲中文字幕无码一区二区三区 | 国产在线第一区二区三区| 国产一区二区三区日韩精品| 久久精品国产亚洲一区二区三区| 精品一区二区三区在线视频| 中文字幕乱码亚洲精品一区| 亚洲第一区在线观看| 一区二区视频在线| 国产成人高清亚洲一区久久| 久久精品国产一区| 欧亚精品一区三区免费| 丰满人妻一区二区三区视频53| 日本午夜精品一区二区三区电影| 日韩一区二区在线免费观看| 久草新视频一区二区三区| 午夜DV内射一区区| 亚洲国产精品一区第二页 | 色狠狠一区二区三区香蕉| 亚洲AV无码一区二区三区鸳鸯影院| 亚洲性日韩精品一区二区三区| 91精品国产一区| 日韩精品无码久久一区二区三| 亚洲综合无码一区二区| 人妻无码一区二区视频| 国产香蕉一区二区在线网站| 香蕉在线精品一区二区| 波多野结衣AV一区二区三区中文 | 日韩精品无码免费一区二区三区| 在线不卡一区二区三区日韩| 精品一区二区三区免费毛片爱| 久久久久国产一区二区| 国产精品亚洲一区二区无码| 亚欧在线精品免费观看一区| 国产在线观看一区二区三区精品| 欧美日韩精品一区二区在线视频 |