亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

徹底搞懂Java多線程(三)

 更新時間:2021年07月03日 16:45:46   作者:保護眼睛  
這篇文章主要給大家介紹了關于Java面試題之多線程和高并發(fā)的相關資料,文中通過示例代碼介紹的非常詳細,對大家學習或者使用java具有一定的參考學習價值,需要的朋友們下面來一起學習學習吧

Java線程池

線程的缺點:

1.線程的創(chuàng)建它會開辟本地方法棧、JVM棧、程序計數器私有的內存,同時消耗的時候需要銷毀以上三個區(qū)域,因此頻繁的創(chuàng)建和銷毀線程比較消耗系統(tǒng)的資源。

2.在任務量遠遠大于線程可以處理的任務量的時候,不能很好的拒絕任務。

所以就有了線程池:

使用池化的而技術來管理和使用線程。

線程池的優(yōu)點

1.可以避免頻繁的創(chuàng)建和銷毀線程

2.可以更好的管理線程的個數和資源的個數。

3.線程池擁有更多的功能,比如線程池可以進行定時任務的執(zhí)行。

4.線程池可以更友好的拒絕不能處理的任務。

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

一共有7種創(chuàng)建方式

創(chuàng)建方式一:

創(chuàng)建固定個數的線程池:

package ThreadPoolDemo;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
 * user:ypc;
 * date:2021-06-13;
 * time: 10:24;
 */
public class ThreadPoolDemo1 {
    public static void main(String[] args) {
        //創(chuàng)建一個固定個數的線程池
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        //執(zhí)行任務
        for (int i = 0; i < 10; i++) {
            executorService.execute(new Runnable() {
                @Override
                public void run() {
                    System.out.println("線程名" + Thread.currentThread().getName());
                }
            });
        }
    }
}

在這里插入圖片描述

那么如果執(zhí)行次數大于10次呢?

線程池不會創(chuàng)建新的線程,它會復用之前的線程。

在這里插入圖片描述

在這里插入圖片描述

那么如果只執(zhí)行兩個任務呢?它創(chuàng)建了是10個線程還是兩個線程呢?

我們可以使用Jconsole來看一看:

在這里插入圖片描述

在這里插入圖片描述

結果是只有2個線程被創(chuàng)建。

創(chuàng)建方式二:

創(chuàng)建帶有緩存的線程池:

適用于短期有大量的任務的時候使用

public class ThreadPoolDemo2 {
    public static void main(String[] args) {
        //創(chuàng)建帶緩存的線程池
        ExecutorService executorService = Executors.newCachedThreadPool();
        for (int i = 0; i < 100; i++) {
            executorService.execute(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName());
                }
            });
        }
    }
}

在這里插入圖片描述

方式三:

創(chuàng)建執(zhí)行定時任務的線程池

package ThreadPoolDemo;
import java.util.Date;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
/**
 * user:ypc;
 * date:2021-06-13;
 * time: 11:32;
 */
public class ThreadPoolDemo3 {
    public static void main(String[] args) {
        ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(2);
        System.out.println("執(zhí)行定時任務前的時間:" + new Date());
        scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                System.out.println("執(zhí)行任務的時間:" + new Date());
            }
        },1,2, TimeUnit.SECONDS);
    }
}

在這里插入圖片描述

執(zhí)行任務的四個參數的意義:

參數1:延遲執(zhí)行的任務

參數2:延遲一段時間后執(zhí)行

參數3:定時任務執(zhí)行的頻率

參數4:配合前兩個參數使用,是2、3參數的時間單位

還有兩種執(zhí)行的方法:

只會執(zhí)行一次的方法:

在這里插入圖片描述

在這里插入圖片描述

第三種的執(zhí)行方式:

在這里插入圖片描述

在這里插入圖片描述

那么這種的執(zhí)行方式和第一種的執(zhí)行方式有什么區(qū)別呢?

當在兩種執(zhí)行的方式中分別加上sleep()之后:

在這里插入圖片描述

方式一:

在這里插入圖片描述

方式三:

在這里插入圖片描述

結論很明顯了:

第一種方式是以上一個任務的開始時間+定時的時間作為當前任務的開始時間

第三種方式是以上一個任務的結束時間來作為當前任務的開始時間。

創(chuàng)建方式四:

package ThreadPoolDemo;
import java.util.Date;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
/**
 * user:ypc;
 * date:2021-06-13;
 * time: 12:38;
 */
public class ThreadPoolDemo4 {
    public static void main(String[] args) {
        //創(chuàng)建單個執(zhí)行任務的線程池
        ScheduledExecutorService scheduledExecutorService
                = Executors.newSingleThreadScheduledExecutor();
        System.out.println("執(zhí)行任務之前" + new Date());
        scheduledExecutorService.scheduleWithFixedDelay(new Runnable() {
            @Override
            public void run() {
                System.out.println("我是SingleThreadSchedule"+ new Date());
            }
        },3,1, TimeUnit.SECONDS);
    }
}

在這里插入圖片描述

在這里插入圖片描述

創(chuàng)建方式五:

創(chuàng)建單個線程的線程池

package ThreadPoolDemo;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
 * user:ypc;
 * date:2021-06-13;
 * time: 12:55;
 */
public class ThreadPoolDemo5 {
    public static void main(String[] args) {
        //創(chuàng)建單個線程的線程池
        ExecutorService executorService = Executors.newSingleThreadExecutor();
        for (int i = 0; i < 20; i++) {
            executorService.execute(new Runnable() {
                @Override
                public void run() {
                    System.out.println("線程名 " +  Thread.currentThread().getName());
                }
            });
        }
    }
}

在這里插入圖片描述

創(chuàng)建單個線程池的作用是什么?

1.可以避免頻繁創(chuàng)建和銷毀線程所帶來的性能的開銷

2.它有任務隊列,可以存儲多余的任務

3.可以更好的管理任務

4.當有大量的任務不能處理的時候,可以友好的執(zhí)行拒絕策略

創(chuàng)建方式六:

創(chuàng)建異步線程池根據當前CPU來創(chuàng)建對應個數的線程池

package ThreadPoolDemo;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
 * user:ypc;
 * date:2021-06-13;
 * time: 13:12;
 */
public class ThreadPoolDemo6 {
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newWorkStealingPool();
        for (int i = 0; i < 10; i++) { 
            executorService.execute(new Runnable() {
                @Override
                public void run() {
                    System.out.println("線程名" + Thread.currentThread().getName());
                }
            });
        }
    }
}

在這里插入圖片描述

運行結果為什么什么都沒有呢?

看下面的異步與同步的區(qū)別就知道了。

加上這個

在這里插入圖片描述

就可以輸出結果了

在這里插入圖片描述

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

前六種的創(chuàng)建方式有什么問題呢?

1.線程的數量不可控(比如帶緩存的線程池)

2.工作任務量不可控(默認的任務隊列的大小時Integer.MAX_VALUE),任務比較大肯會導致內存的溢出。

所以就可以使用下面的創(chuàng)建線程池的方式了:

package ThreadPoolDemo;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
 * user:ypc;
 * date:2021-06-13;
 * time: 15:05;
 */
public class ThreadPoolDemo7 {
    private static int threadId = 0;
    public static void main(String[] args) {
        ThreadFactory threadFactory = new ThreadFactory() {
            @Override
            public Thread newThread(Runnable r) {
                Thread thread = new Thread(r);
                thread.setName("我是threadPool-" + ++threadId);
                return thread;
            }
        };
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(3, 3, 100,
                TimeUnit.MILLISECONDS, new LinkedBlockingDeque<>(12),
                threadFactory, new ThreadPoolExecutor.AbortPolicy());
        for (int i = 0; i < 15; i++) {
            threadPoolExecutor.execute(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName());
                }
            });
        }
    }
}

在這里插入圖片描述

參數說明:

在這里插入圖片描述

  • 參數一:核心線程數|線程池正常情況下的線程 數量
  • 參數二:最大線程數|當有大量的任務的時候可以創(chuàng)建的最多的線程數
  • 參數三:最大線程的存活時間
  • 參數四:配合參數三一起使用的表示參數三的時間單位
  • 參數五:任務隊列
  • 參數六:線程工廠
  • 參數七:決絕策略

注意事項:最大的線程數要大于等于核心的線程數

在這里插入圖片描述

在這里插入圖片描述

五種拒絕策略

在這里插入圖片描述

在這里插入圖片描述

為什么拒絕策略可以舍棄最新的任務或者最舊的任務呢?

因為LinkedBlockingDeque時FIFO的。

第五種:自定義的拒絕策略

在這里插入圖片描述

在這里插入圖片描述

ThreadPoolExecutor的執(zhí)行方式

在這里插入圖片描述

package ThreadPoolDemo;
import java.util.concurrent.*;
/**
 * user:ypc;
 * date:2021-06-13;
 * time: 16:58;
 */
public class ThreadPoolDemo9 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(3, 4, 100,
                TimeUnit.MILLISECONDS, new LinkedBlockingDeque<>(10), new ThreadPoolExecutor.DiscardOldestPolicy());

        //線程池的執(zhí)行方式一
        threadPoolExecutor.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println("使用了execute()執(zhí)行了線程池");
            }
        });
        //線程池的執(zhí)行方式二
        Future<String> futureTask =
                threadPoolExecutor.submit(new Callable<String>() {
                    @Override
                    public String call() throws Exception {
                        return "使用submit(new Callable<>())執(zhí)行了線程池";
                    }
                });
        System.out.println(futureTask.get());
        
    }
}

無返回值的執(zhí)行方式

在這里插入圖片描述

有返回值的執(zhí)行方式

在這里插入圖片描述

ThreadPoolExecutor的執(zhí)行流程

當任務量小于核心線程數的時候,ThreadPoolExecutor會創(chuàng)建線程來執(zhí)行任務

當任務量大于核心的線程數的時候,并且沒有空閑的線程時候,且當線程池的線程數小于最大線程數的時候,此時會將任務存

放到任務隊列中

如果任務隊列也被存滿了,且最大線程數大于線程池的線程數的時候,會創(chuàng)建新的線程來執(zhí)行任務。

如果線程池的線程數等于最大的線程數,并且任務隊列也已經滿了,就會執(zhí)行拒絕策略。👇

在這里插入圖片描述

線程池的終止

shutdown()

線程池的任務會執(zhí)行完

shutdownNow()

立即終止線程池,線程池的任務不會執(zhí)行完

線程池的狀態(tài)

在這里插入圖片描述

異步、同步

1.Java 線程 同步與異步

多線程并發(fā)時,多個線程同時請求同一個資源,必然導致此資源的數據不安全,A線程修改了B線程的處理的數據,而B線程又修改了A線程處理的數理。顯然這是由于全局資源造成的,有時為了解決此問題,優(yōu)先考慮使用局部變量,退而求其次使用同步代碼塊,出于這樣的安全考慮就必須犧牲系統(tǒng)處理性能,加在多線程并發(fā)時資源掙奪最激烈的地方,這就實現了線程的同步機制

同步

A線程要請求某個資源,但是此資源正在被B線程使用中,因為同步機制存在,A線程請求不到,怎么辦,A線程只能等待下去

異步

A線程要請求某個資源,但是此資源正在被B線程使用中,因為沒有同步機制存在,A線程仍然請求的到,A線程無需等待同步的方式:

1.發(fā)送請求

2.等待執(zhí)行完成

3.有結果的返回

異步的方式

1.發(fā)請求

2.執(zhí)行完成

3.另一個線程異步處理

4.處理完成之后返回回調結果

顯然,同步最最安全,最保險的。而異步不安全,容易導致死鎖,這樣一個線程死掉就會導致整個進程崩潰,使用異步的機制,性能會有所提升

線程工廠

設想這樣一種場景,我們需要一個線程池,并且對于線程池中的線程對象,賦予統(tǒng)一的線程優(yōu)先級、統(tǒng)一的名稱、甚至進行統(tǒng)一的業(yè)務處理或和業(yè)務方面的初始化工作,這時工廠方法就是最好用的方法了

package ThreadPoolDemo;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
/**
 * user:ypc;
 * date:2021-06-13;
 * time: 11:12;
 */
public class ThreadFactoryDemo {
    public static void main(String[] args) {
        MyThreadFactory myThreadFactory = new MyThreadFactory();
        ExecutorService executorService =  Executors.newFixedThreadPool(10,myThreadFactory);
        for (int i = 0; i < 10; i++) {
            executorService.execute(new Runnable() {
                @Override
                public void run() {
                    System.out.println("使用線程工廠設置的線程名:"+ Thread.currentThread().getName() +
                            " 使用線程工廠設置的線程的優(yōu)先級" + Thread.currentThread().getPriority());
                }
            });
        }

    }
    private static int count = 0;
     static class MyThreadFactory implements ThreadFactory{
         @Override
         public Thread newThread(Runnable r) {
             Thread thread = new Thread(r);
             thread.setPriority(8);
             thread.setName("thread--" + count++);
             return thread;
         }
     }
}

在這里插入圖片描述

總結

本篇文章就到這里了,希望可以對你有所幫助,也希望您能夠多多關注腳本之家的更多內容!

相關文章

  • java設計模式之工廠方法模式

    java設計模式之工廠方法模式

    這篇文章主要為大家詳細介紹了java設計模式之工廠方法模式,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-08-08
  • Java中方法作為參數傳遞的方式

    Java中方法作為參數傳遞的方式

    這篇文章主要介紹了Java如何讓方法作為參數傳遞,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-05-05
  • Java使用ThreadLocal實現當前登錄信息的存取功能

    Java使用ThreadLocal實現當前登錄信息的存取功能

    ThreadLocal和其他并發(fā)工具一樣,也是用于解決多線程并發(fā)訪問,下這篇文章主要給大家介紹了關于Java使用ThreadLocal實現當前登錄信息的存取功能,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下
    2023-02-02
  • 聊聊Spring循環(huán)依賴三級緩存是否可以減少為二級緩存的情況

    聊聊Spring循環(huán)依賴三級緩存是否可以減少為二級緩存的情況

    這篇文章主要介紹了聊聊Spring循環(huán)依賴三級緩存是否可以減少為二級緩存的情況,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-02-02
  • Java8新特性之方法引用的實踐指南

    Java8新特性之方法引用的實踐指南

    這篇文章主要給大家介紹了關于Java8新特性之方法引用的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2021-03-03
  • java 輸入3個數a,b,c,按大小順序輸出的實例講解

    java 輸入3個數a,b,c,按大小順序輸出的實例講解

    今天小編就為大家分享一篇java 輸入3個數a,b,c,按大小順序輸出的實例講解,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-07-07
  • Java list利用遍歷進行刪除操作3種方法解析

    Java list利用遍歷進行刪除操作3種方法解析

    這篇文章主要介紹了Java list利用遍歷進行刪除操作3種方法解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-01-01
  • Java實現特定范圍的完數輸出算法示例

    Java實現特定范圍的完數輸出算法示例

    這篇文章主要介紹了Java實現特定范圍的完數輸出算法,簡單說明了完數的概念、計算原理并結合實例形式分析了java針對給定范圍內的完數輸出操作實現技巧,需要的朋友可以參考下
    2017-12-12
  • Spring在多線程環(huán)境下如何確保事務一致性問題詳解

    Spring在多線程環(huán)境下如何確保事務一致性問題詳解

    這篇文章主要介紹了Spring在多線程環(huán)境下如何確保事務一致性問題詳解,說到異步執(zhí)行,很多小伙伴首先想到Spring中提供的@Async注解,但是Spring提供的異步執(zhí)行任務能力并不足以解決我們當前的需求,需要的朋友可以參考下
    2023-11-11
  • 解決springboot MultipartFile文件上傳遇到的問題

    解決springboot MultipartFile文件上傳遇到的問題

    本文給大家?guī)砹私鉀Qspringboot MultipartFile文件上傳遇到的問題,解決方法超簡單,感興趣的朋友參考下本文
    2018-08-08

最新評論