最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

非常適合新手學生的Java線程池超詳細分析

 更新時間:2022年03月21日 11:44:08   作者:摸魚打醬油  
作者是一個來自河源的大三在校生,以下筆記都是作者自學之路的一些淺薄經(jīng)驗,如有錯誤請指正,將來會不斷的完善筆記,幫助更多的Java愛好者入門

線程池的好處

  • 可以實現(xiàn)線程的復用,避免重新創(chuàng)建線程和銷毀線程。創(chuàng)建線程和銷毀線程對CPU的開銷是很大的。
  • 可以限制最大可創(chuàng)建的線程數(shù),可根據(jù)自己的機器性能動態(tài)調(diào)整線程池參數(shù),提高應用性能。
  • 提供定時執(zhí)行、并發(fā)數(shù)控制等功能。
  • 統(tǒng)一管理線程。

創(chuàng)建線程池的五種方式

1:緩存線程池(不推薦)

2:固定容量線程池(不推薦)

3:單個線程池(不推薦)

4:定時任務線程池(不推薦)

5:通過ThreadPoolExecutor構(gòu)造方法創(chuàng)建線程池(阿里巴巴開發(fā)手冊十分推薦)

前面4種創(chuàng)建線程池的方式都是通過Executors的靜態(tài)方法來創(chuàng)建。

緩存線程池CachedThreadPool

	ExecutorService executorService = Executors.newCachedThreadPool();

        for (int i = 0; i < 10; i++) {
            final int finalI = i;
            executorService.execute(new Runnable() {
                public void run() {
                    System.out.println(Thread.currentThread().getName()+"<thread->run>"+ finalI);
                }
            });
        }

為什么不推薦使用緩存線程池?

源碼分析

public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, 2147483647, 60L, TimeUnit.SECONDS, new SynchronousQueue());
    }
 public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, Executors.defaultThreadFactory(), defaultHandler);
    }

通過上面兩個代碼片段,我們可以看出CachedThreadPool的maximumPoolSize為Integer的最大值2147483647,相當于可以無限的創(chuàng)建線程,而創(chuàng)建線程是需要內(nèi)存的,這樣就會造成內(nèi)存溢出,而且一般的機器也沒用那么大的內(nèi)存給它創(chuàng)建這么大量的線程。

固定容量線程池FixedThreadPool

newFixedThreadPool(int num),num就是我們要指定的固定線程數(shù)量

	ExecutorService executorService = Executors.newFixedThreadPool(5);

      for (int i = 0; i < 10; i++) {
          final int finalI = i;
          executorService.execute(new Runnable() {
              public void run() {
                  System.out.println(Thread.currentThread().getName()+"<thread->run>"+ finalI);
              }
          });
      }

輸出:

pool-1-thread-5<thread->run>4
pool-1-thread-4<thread->run>3
pool-1-thread-5<thread->run>5
pool-1-thread-3<thread->run>2
pool-1-thread-3<thread->run>8
pool-1-thread-3<thread->run>9
pool-1-thread-2<thread->run>1
pool-1-thread-1<thread->run>0
pool-1-thread-5<thread->run>7
pool-1-thread-4<thread->run>6

可以看出起到了線程的復用。

為什么FixedThreadPool是固定線程池?

源碼分析

public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue());
    }

通過這個源碼可以看出,核心線程數(shù)(corePoolSize)和最大線程數(shù)(maximumPoolSize)都為nThreads,因為只有這樣,線程池才不會進行擴容,線程數(shù)才固定。

單個線程池SingleThreadExecutor

	ExecutorService executorService = Executors.newSingleThreadExecutor();

      for (int i = 0; i < 10; i++) {
          final int finalI = i;
          executorService.execute(new Runnable() {
              public void run() {
                  System.out.println(Thread.currentThread().getName()+"<thread->run>"+ finalI);
              }
          });

      }

為什么SingleThreadExecutor只含有一個線程?

源碼分析

public static ExecutorService newSingleThreadExecutor() {
        return new Executors.FinalizableDelegatedExecutorService(new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue()));
    }

通過這個源碼可以看出,核心線程數(shù)(corePoolSize)和最大線程數(shù)(maximumPoolSize)都為1,所以它只含有一個線程。

定時任務線程池ScheduledThreadPool

	  int initDelay=10; //初始化延時
      int period=1;//初始化延遲過了之后,每秒的延時

      ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(10);

      scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
          @Override
          public void run() {
              System.out.println(Thread.currentThread().getName()+"<thread->run>");
          }
      },initDelay,period, TimeUnit.SECONDS);

這段代碼的效果是:程序運行之后等10秒,然后輸出第一次結(jié)果,之后每隔1秒輸出一次結(jié)果。

為什么不推薦使用ScheduledThreadPool?

源碼分析

public ScheduledThreadPoolExecutor(int corePoolSize) {
        super(corePoolSize, 2147483647, 10L, TimeUnit.MILLISECONDS, new ScheduledThreadPoolExecutor.DelayedWorkQueue());
    }

可以看出ScheduledThreadPool的最大線程數(shù)(maximumPoolSize)為Integer的最大值2147483647,相當于可以無限的創(chuàng)建線程,而創(chuàng)建線程是需要內(nèi)存的,這樣就會造成內(nèi)存溢出,而且一般的機器也沒用那么大的內(nèi)存給它創(chuàng)建這么大量的線程。

ThreadPoolExecutor創(chuàng)建線程池(十分推薦)

	ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10, 20,
              2L, TimeUnit.SECONDS, new ArrayBlockingQueue<>(5),
              Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());

      for (int i = 0; i < 12; i++) {
          final int finalI = i;
          threadPoolExecutor.execute(new Runnable() {
              public void run() {
                  System.out.println(Thread.currentThread().getName()+"<thread->run>"+ finalI);
              }
          });
      }

ThreadPoolExecutor的七個參數(shù)詳解

	public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) {
        
    }
  • corePoolSize:核心線程數(shù)。這些線程一旦被創(chuàng)建不會被銷毀,是一直存在的。線程池默認是沒有線程的,當有任務到來了,就會通過ThreadFactory去創(chuàng)建線程,并一直存在。
  • maximumPoolSize:最大線程數(shù)。非核心線程數(shù)=maximumPoolSize-corePoolSize,非核心線程數(shù)其實就是可擴容的線程數(shù),可能會被銷毀。
  • keepAliveTime:非核心線程的空閑存活時間。當通過擴容生成的非核心線程數(shù)在keepAliveTime這個時間后還處于空閑狀態(tài),則會銷毀這些非核心線程。
  • unit:keepAliveTime的時間單位,例如:秒
  • workQueue:等待區(qū)。當來了>corePoolSize的任務時會把任務存放在workQueue這個阻塞隊列中,等待其他線程處理。
  • threadFactory:線程工廠。創(chuàng)建線程的一種方式。
  • handler:拒絕策略。當來了>最大線程數(shù)+workQueue的容量則會執(zhí)行拒絕策略

workQueue

ArrayBlockingQueue:有界阻塞隊列。隊列有大小限制,當容量超過時則會觸發(fā)擴容或者拒絕策略。

	public ArrayBlockingQueue(int capacity) {
        this(capacity, false);
    }

LinkedBlockingQueue:無界阻塞隊列,隊列無大小限制,可能會造成內(nèi)存溢出。

	 public LinkedBlockingQueue() {
        this(2147483647);
    }

handler

AbortPolicy:直接拋異常

	public static class AbortPolicy implements RejectedExecutionHandler {
        public AbortPolicy() {
        }

        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            throw new RejectedExecutionException("Task " + r.toString() + " rejected from " + e.toString());
        }
    }

DiscardPolicy:不作任何操作。默默丟棄任務

	public static class DiscardPolicy implements RejectedExecutionHandler {
        public DiscardPolicy() {
        }

        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
        }
    }

DiscardOldestPolicy:丟掉存在時間最長的任務

	public static class DiscardOldestPolicy implements RejectedExecutionHandler {
        public DiscardOldestPolicy() {
        }

        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            if (!e.isShutdown()) {
                e.getQueue().poll();
                e.execute(r);
            }

        }
    }

CallerRunsPolicy:讓提交任務的線程去處理任務

	public static class CallerRunsPolicy implements RejectedExecutionHandler {
        public CallerRunsPolicy() {
        }

        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            if (!e.isShutdown()) {
                r.run();
            }

        }
    }

threadFactory

	ThreadFactory threadFactory = Executors.defaultThreadFactory();

      threadFactory.newThread(new Runnable() {
          @Override
          public void run() {
              System.out.println("threadFactory");
          }
      }).start();

如何觸發(fā)拒絕策略和線程池擴容?

	ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10, 20,
              2L, TimeUnit.SECONDS, new ArrayBlockingQueue<>(5),
              Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());

      for (int i = 0; i < 26; i++) { //并發(fā)數(shù)26
          final int finalI = i;
          threadPoolExecutor.execute(new Runnable() {
              public void run() {
                  System.out.println(Thread.currentThread().getName()+"<thread->run>"+ finalI);
              }
          });
      }
      /**
       * 核心線程數(shù)=10,最大線程數(shù)=20,故可擴容線程數(shù)=20-10
       * BlockingQueue的大小為5,故等待區(qū)的大小為5,也就是當并發(fā)數(shù)<=核心線程數(shù)+5不會擴容,并發(fā)數(shù)大于16才會擴容
       *
       * 觸發(fā)擴容:并發(fā)數(shù)>核心線程數(shù)+阻塞隊列的大小
       * 對于這段代碼,如果來了26個并發(fā),10個并發(fā)會被核心線程處理,5個會在等待區(qū),剩下11個會因為等待區(qū)滿了而觸發(fā)擴容
       * 因為這里最多能夠擴容10個,這里卻是11個,所以會觸發(fā)拒絕策略
       */
  • 為什么這段代碼會觸發(fā)拒絕策略

對于這段代碼,如果來了26個并發(fā),10個并發(fā)會被核心線程處理,5個會在等待區(qū),剩下11個會因為等待區(qū)滿了而觸發(fā)擴容,但是又因為因為這里最多能夠擴容10個,這里卻是11個,所以會觸發(fā)拒絕策略。

  • 怎么觸發(fā)擴容

觸發(fā)擴容:并發(fā)數(shù)>核心線程數(shù)(corePoolSize)+阻塞隊列(workQueue)的大小

  • 使用Java純手寫一個線程池

下期文章鏈接http://m.fzitv.net/article/241589.htm

到此這篇關(guān)于非常適合新手學生的Java線程池超詳細分析的文章就介紹到這了,更多相關(guān)Java 線程池內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論

新干县| 凤翔县| 社旗县| 盐津县| 饶平县| 辰溪县| 咸丰县| 宁波市| 印江| 云浮市| 阳春市| 禹州市| 山阴县| 渭南市| 井冈山市| 丰县| 广河县| 株洲市| 乐东| 嘉定区| 加查县| 长岭县| 丹寨县| 惠安县| 甘泉县| 南和县| 北碚区| 陇川县| 襄汾县| 固阳县| 来安县| 许昌市| 西昌市| 安岳县| 遵义县| 额敏县| 财经| 云霄县| 辽源市| 辛集市| 疏勒县|