日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > windows >内容正文

windows

JUC并发编程学习笔记(十)线程池(重点)

發布時間:2023/11/16 windows 52 coder
生活随笔 收集整理的這篇文章主要介紹了 JUC并发编程学习笔记(十)线程池(重点) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

線程池(重點)

線程池:三大方法、七大參數、四種拒絕策略

池化技術

程序的運行,本質:占用系統的資源!優化資源的使用!-> 池化技術(線程池、連接池、對象池......);創建和銷毀十分消耗資源

池化技術:事先準備好一些資源,有人要用就拿,拿完用完還給我。

線程池的好處:

1、降低資源消耗

2、提高相應速度

3、方便管理

線程復用、可以控制最大并發數、管理線程

線程池:三大方法

1、newSingleThreadExecutor

單列線程池,只有一條線程;

單例線程池配合callable使用,注意需要在程序運行結束后關閉線程池

package org.example.pool;

import java.util.concurrent.*;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

//Executors->工具類
public class Demo01 {
    public static void main(String[] args) {
        TestCallable able = new TestCallable();

        //三大方法
        ExecutorService threadPool = Executors.newSingleThreadExecutor();//單個線程


        try {
            for (int i = 0; i < 10; i++) {
                FutureTask<String> task = new FutureTask<String>(able);

                //線程池創建線程
                threadPool.execute(task);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //線程池用完,程序結束,關閉線程池
            threadPool.shutdown();
        }


//        Executors.newFixedThreadPool(5);//固定線程池大小
//        Executors.newCachedThreadPool();//可伸縮的線程池
    }
}

class TestCallable implements Callable<String> {
    Lock lock = new ReentrantLock();

    @Override
    public String call() throws Exception {
        TimeUnit.SECONDS.sleep(2);
        System.out.println(Thread.currentThread().getName() + ":ok");
        return Thread.currentThread().getName() + ":ok";
    }
}

注意結果圖

在單例線程池中,運行結果發現都是同一條線程在操作資源,整個線程池中只有一條pool-1-thread-1線程。

2、newFixedThreadPool

同樣的代碼,將線程池切換為固定大小的線程池,設置為5條,這樣跑出來的結果又不一樣

由于設置了線程休眠,所以會導致比較平均的結果出現,但是一般情況下都是五條線程搶占資源,每次結果都是不一定的,看那條線程處理的比較快搶占的比較多。

3、newCachedThreadPool

同樣的代碼,將線程池切換為可伸縮大小的線程池,這樣跑出來的結果又不一樣

根據業務代碼生成具體條數的線程:如本次業務通過循環或其他因數,同時需要處理10條任務,那么當你線程池中的第一條線程還未完成任務時就會生成一條新的線程來同步處理這些任務,只要你cpu處理速度夠快那么理論最高可能同時生成一個具有10條線程(任務數)的一個線程池。

七大參數

源碼分析

public static ExecutorService newSingleThreadExecutor() {
    return new FinalizableDelegatedExecutorService
        (new ThreadPoolExecutor(1, 1,
                                0L, TimeUnit.MILLISECONDS,
                                new LinkedBlockingQueue<Runnable>()));
}
public static ExecutorService newFixedThreadPool(int nThreads) {
    //和以上沒有區別,只是通過用戶調用來完成的,相當于new ThreadPoolExecutor(5, 5,....)
    return new ThreadPoolExecutor(nThreads, nThreads,
                                  0L, TimeUnit.MILLISECONDS,
                                  new LinkedBlockingQueue<Runnable>());
}
public static ExecutorService newCachedThreadPool() {
    //設置了默認是0個線程,但是最大值可以達到大約21億條,設置了Integer.MAX_VALUE(約21億)
    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,//如果通過Integer.MAX_VALUE來跑線程池一定會照成OOM(溢出)
                                  60L, TimeUnit.SECONDS,
                                  new SynchronousQueue<Runnable>());
}

通過觀察以上三大方法的創建線程池方式,可以發現,三大方法的本質都是調用ThreadPoolExecutor來創建的

public ThreadPoolExecutor(int corePoolSize,//核心線程池大小
                          int maximumPoolSize,//最大線程池大小
                          long keepAliveTime,//超時無調用釋放
                          TimeUnit unit,//超時單位
                          BlockingQueue<Runnable> workQueue,//阻塞隊列
                          ThreadFactory threadFactory,//線程工廠,創建線程的,一般不用動
                          RejectedExecutionHandler handler) {//拒絕策略
    if (corePoolSize < 0 ||
        maximumPoolSize <= 0 ||
        maximumPoolSize < corePoolSize ||
        keepAliveTime < 0)
        throw new IllegalArgumentException();
    if (workQueue == null || threadFactory == null || handler == null)
        throw new NullPointerException();
    this.corePoolSize = corePoolSize;
    this.maximumPoolSize = maximumPoolSize;
    this.workQueue = workQueue;
    this.keepAliveTime = unit.toNanos(keepAliveTime);
    this.threadFactory = threadFactory;
    this.handler = handler;
}

這就是為什么阿里巴巴開發規范中說不要使用Executors來創建線程池而是讓我們通過ThreadPoolExecutor來創建,其實就是讓我們通過了解線程池的本質來避免一些問題。

模擬銀行業務模塊模擬

package org.example.pool;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class Demo02 {
    public static void main(String[] args) {
        //自定義線程池,工作中只會使用ThreadPoolExecutor
        ThreadPoolExecutor threadPool = new ThreadPoolExecutor(2,
                5,
                3,
                TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(3),
                new ThreadPoolExecutor.AbortPolicy());//拒絕策略,即當阻塞隊列和線程池線程都已經最大化運行沒有任何位置可以處置接下來的元素了,就拒絕該元素進入并拋出異常
        try {
            //最大承載 隊列Queue+max
            for (int i = 0; i < 10; i++) {
                //線程池創建線程
                threadPool.execute(()->{
                    System.out.println(Thread.currentThread().getName() + ":ok");
                });
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //線程池用完,程序結束,關閉線程池
            threadPool.shutdown();
        }
    }
}

此時有10個任務,但是最大線程量只有5個,阻塞隊列量只有三個,所以注定會有兩個無法處理,此時觸發拒絕策略,拋出異常并且拒絕該任務。

可以看到執行了八個任務,通過五條不同的線程。執行了拒絕策略拋出了異常java.util.concurrent.RejectedExecutionException

四種拒絕策略

四種拒絕策略的描述

//AbortPolicy 隊列滿了,丟掉任務,拋出異常
//CallerRunsPolicy 哪條線程給的任務回到哪條線程去執行,線程池不執行
//DiscardPolicy 隊列滿了,丟掉任務,但不拋出異常
//DiscardOldestPolicy 隊列滿了,嘗試去和最早的競爭,如果沒成功,依舊丟棄任務,但不拋出異常

小結和拓展

了解:IO密集型、cpu密集型(調優)

/*
* 最大線程到底該如何定義
* 1、CPU 密集型,幾何就定義為幾,就可以保證cpu效率最高的
* 2、IO 密集型 > 判斷你程序中十分耗IO的線程,
* 程序    15個大小任務 io十分占用資源
* */

總結

以上是生活随笔為你收集整理的JUC并发编程学习笔记(十)线程池(重点)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。