Java十分鐘入門多線程下篇

 更新時間:2022年03月10日 11:58:19   作者:熱愛飛行的小應學長  
哈嘍大家好,Java十分鐘入門多線程下篇來啦,上一篇文章介紹到了多線程的調度和同步、鎖,有了鎖之后就可以讓數據共享變的更安全。這一篇文章先來介紹一下線程池

1、線程池:

什么是線程池?

咱們也不看長篇大論,通俗的來講,線程池就是裝線程的容器,當需要用的時候去池里面取出來,不用的時候放回去或者銷毀。這樣一個線程就可以反復的利用,通過線程的這種反復利用機制,可以有效地避免直接創建線程所帶來的壞處。

線程池有什么好處?

  • 降低了資源的消耗(CPU)
  • 提高任務執行的響應速度
  • 提高線程的可管理性

線程池創建流程圖:

其實通過這個圖就可以看到線程池的處理過程:

  • 有新任務進來,判斷核心線程池是否滿了,是:進入排,否:創建任務
  • 在等待隊列判斷是否排滿了,是:進入線程池 ,否:任務加入隊列
  • 判斷線程池是否滿了,是:拒絕執行任務,否:創建線程執行

2、創建線程池:

先看一下官網給出的創建方法(部分):

完整的可以參考官方文檔:

https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/concurrent/Executors.html

這里介紹四種常用的創建類型:

  • newCacheThreadPool(創建一個可緩存的線程池,有任務時才會創建新的線程)
  • newSingleThreadExecutor(創建一個單線程池,線程池中只有一個線程)
  • newFixedThreadPool(int a) (創建固定線程數量的線程池,輸入參數:int類型)
  • newScheduledTreadPool (創建一個固定長度的線程池,并且以延時或定時的方式來執行線程)

1、newCacheThreadPool:

創建可緩存的線程對象,意思是這個任務需要幾個線程來處理,就會創建幾個線程:

線程需要執行的類:

public class MyRunnable implements Runnable{

    int num;

    public MyRunnable(int num) {
        this.num = num;
    }

    @Override
    public void run() {
        
        System.out.println(Thread.currentThread().getName()+"執行了:"+num);
    }
}

測試類:

public class Test {
    public static void main(String[] args) {

        //創建單個線程池對象,里面線程只有一個
        ExecutorService cachedService = Executors.newCachedThreadPool();

        //執行5個任務
        for (int i = 1; i<= 5; i++) {
            cachedService.execute(new MyRunnable(i));
        }
    }
}

來看看結果:

OK,上述代碼線程池用了5個線程來處理,那么如果我們在每次運行前加一次線程休眠會怎么樣? 在每次執行后需要休眠0.5秒(500毫秒):

public class Test {
    public static void main(String[] args) {
    
        //創建一個緩存的線程池對象
       
        ExecutorService cachedService = Executors.newCachedThreadPool();
        
        for (int i = 1; i<= 5; i++) {
                cachedService.execute(new MyRunnable(i));
                //線程休眠:
                try{
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
        }
    }
}

看看結果:

小結:

  • 如果沒有加線程休眠,線程池默認會創建多個線程池對象來幫你完成任務,執行更快完成并且銷毀內存,釋放資源。
  • 如果添加了線程休眠,線程池會認為同少量的線程對象就可以完成這個任務,就不會幫你創建多個線程對象(因為時間足夠,就沒必要再創建)

2、newSingleThreadExecutor:

這個方法是創建只有一個線程的線程池,不管怎么樣,多只有一個線程來幫你執行任務:

public class Test {
    public static void main(String[] args) {

        //創建單個線程池對象,里面線程只有一個
        ExecutorService singleService = Executors.newSingleThreadExecutor();

        //執行一百萬次任務
        for (int i = 1; i<= 1000000; i++) {
            singleService.execute(new MyRunnable(i));
        }
    }
}

看看結果:

對吧,執行了1000000次也是一個線程在執行,因為這個線程池里面只有一個線程呀。

3、newFixedThreadPool(int a):

這個方法就是創建固定線程數的線程池,比如我要一個這個池里面有10個線程,在后面輸入參數即可:

public class Test {
    public static void main(String[] args) {

        //線程池創建固定數量的線程對象來執行任務,這里創建10個線程對象,由線程池管理生命周期
        ExecutorService singleService = Executors.newFixedThreadPool(10);
        //執行10個任務
        for (int i = 1; i<= 100; i++) {
            singleService.execute(new MyRunnable(i));
        }
    }
}

看看結果:

4、newScheduledTreadPool :

創建一個固定長度的線程池,并且以延時或定時的方式來執行線程,也就是說使用這個方法創建的線程池可以自定義每次執行的時間:

Demo:

public class MyRunnable implements Runnable{

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"延遲5秒執行,并且每2秒執行一次該任務:");
    }
}

測試類:

public class Test {
    public static void main(String[] args) {

        //線程池創建一個定時任務的線程對象
        ScheduledExecutorService service = Executors.newScheduledThreadPool(4);
        /**
         *定時器執行的任務,并且按周期執行
         * 參數1:線程任務
         * 參數2:5秒之后開始執行
         * 參數3:執行后每2秒為一個周期去循環執行
         * 參數4:時間單位。枚舉類型,我這指定秒(可以參考API)
         */
        service.scheduleAtFixedRate(new MyRunnable(),5,1, TimeUnit.SECONDS);
    }
}

看看結果:

3、線程池創建自定義線程:

當以上四種線程池滿不足業務需求的時候,咱們也可以自定義線程池:

先來一個線程執行類:

public class MyRunnable implements Runnable{

    int num;

    public MyRunnable(int i) {

        this.num = num;
    }

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"執行了"+num);
    }
}

測試類:

public class Test {
    public static void main(String[] args) {

        /**
         * 參數1:線程池有5個固定的線程對象
         * 參數2:當線程池的線程忙不過來的時候,最大線程數為7,也就是說線程對象就可以增加到7個(其中2個是臨時線程)
         * 參數3:當臨時線程對象超出300毫秒的時候還沒有接到新任務,線程池就自動 銷毀臨時的線程對象
         * 參數4:時間單位。這指定秒,具體參考TimeUnit的枚舉類型
         * 參數5:等待執行的任務序列4個(其中有4個任務序列等待線程池對象來執行任務)
         */

        ThreadPoolExecutor executor = new ThreadPoolExecutor(5,7,300, 
        					TimeUnit.SECONDS,new ArrayBlockingQueue<Runnable>(4));

        for (int i = 0; i < 6; i++) {
            executor.execute(new MyRunnable(i));
            showInfo(executor);
        }
    }

	//獲取線程的一些信息
    private static void showInfo(ThreadPoolExecutor executor) {
        System.out.println("線程池的總數量:"+executor.getPoolSize());
        System.out.println("隊列中等待執行的任務數:"+executor.getQueue().size());
        System.out.println("已經執行完畢的任務數:"+executor.getCompletedTaskCount());
        System.out.println("---------");
    }
}

4、Runnable和Callable的區別:

Runnable是不返還值的,而Callable可以返回值,具體可以看這篇博客(其實主要我也沒深入學習這個哈哈): Runnable和Callable的區別

5、線程池總結:

通過這個文章,咱們對線程池有了基礎的了解,如何去創建和使用,但這僅僅是最簡單的,線程是一個復雜的東西,大家也可以參考其他技術博客來深入學習和研究,在創建線程池的時候,根據場景,合理設置線程池的各個參數,包括線程池數量、隊列、線程工廠和拒絕策略,讓資源更好的利用起來,這也是優化性能的關鍵。

到此這篇關于Java十分鐘入門多線程下篇的文章就介紹到這了,更多相關Java 多線程內容請搜索腳本之家以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • 淺談MyBatis3 DynamicSql風格語法使用指南

    淺談MyBatis3 DynamicSql風格語法使用指南

    這篇文章主要介紹了淺談MyBatis3 DynamicSql風格語法使用指南,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2021-03-03
  • Spring boot GC實現過程原理解析

    Spring boot GC實現過程原理解析

    這篇文章主要介紹了Spring boot GC實現過程原理解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-08-08
  • spring?IOC容器管理必須知道的一些操作(基于XML方式)

    spring?IOC容器管理必須知道的一些操作(基于XML方式)

    Spring框架的核心是Spring容器,容器創建對象,將它們裝配在一起,配置它們并管理它們的完整生命周期,下面這篇文章主要給大家介紹了關于spring?IOC容器管理必須知道的一些操作,需要的朋友可以參考下
    2022-03-03
  • SpringBoot使用@ResponseBody返回圖片的實現

    SpringBoot使用@ResponseBody返回圖片的實現

    這篇文章主要介紹了SpringBoot使用@ResponseBody返回圖片的實現,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-11-11
  • 使用springmvc運行流程分析,手寫spring框架嘗試

    使用springmvc運行流程分析,手寫spring框架嘗試

    這篇文章主要介紹了使用springmvc運行流程分析,手寫spring框架嘗試,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-10-10
  • 詳解Spring Boot 屬性配置和使用

    詳解Spring Boot 屬性配置和使用

    本篇文章主要介紹了詳解Spring Boot 屬性配置和使用,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-06-06
  • java使用Apache工具集實現ftp文件傳輸代碼詳解

    java使用Apache工具集實現ftp文件傳輸代碼詳解

    這篇文章主要介紹了java使用Apache工具集實現ftp文件傳輸代碼詳解,分享了詳細連接ftp server和上傳文件,下載文件的代碼,以及結果展示,具有一定借鑒價值,需要的朋友可以參考下。
    2017-12-12
  • springboot實現yml里的自定義配置方法

    springboot實現yml里的自定義配置方法

    這篇文章主要介紹了springboot實現yml里的自定義配置方法,主要介紹三種,字符串配置,數組配置和帶默認值的配置,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-01-01
  • MyBatis實現批量插入數據,多重forEach循環

    MyBatis實現批量插入數據,多重forEach循環

    這篇文章主要介紹了MyBatis實現批量插入數據,多重forEach循環方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-02-02
  • Spring Core動態代理的實現代碼

    Spring Core動態代理的實現代碼

    通過JDK的Proxy方式或者CGLIB方式生成代理對象的時候,相關的攔截器已經配置到代理對象中去了,接下來通過本文給大家介紹Spring Core動態代理的相關知識,需要的朋友可以參考下
    2021-10-10

最新評論

免费人成视频在线观看