国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

JavaEE & 線程案例 & 定時器 & 線程池 and 工廠模式

這篇具有很好參考價值的文章主要介紹了JavaEE & 線程案例 & 定時器 & 線程池 and 工廠模式。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

  • 歡迎光臨 ^ V ^

JavaEE & 線程案例 & 定時器 & 線程池 and 工廠模式

JavaEE & 線程案例 & 定時器 & 線程池 and 工廠模式

1. 定時器

  • 定時器,可以理解為鬧鐘
    • 我們設(shè)立一個時間,時間一到,讓一個線程跑起來~
  • 而Java標準庫提供了一個定時器類:
    • Timer ,from java.util

JavaEE & 線程案例 & 定時器 & 線程池 and 工廠模式

1.1 定時器Timer的使用

1.1.1 核心方法schedule

JavaEE & 線程案例 & 定時器 & 線程池 and 工廠模式

  • 傳入任務(wù)引用(TimerTask task)和 “定時”(long delay / ms)

JavaEE & 線程案例 & 定時器 & 線程池 and 工廠模式

  • 由于TimerTask不是函數(shù)式接口,是普通的抽象類
    • 所以只能用匿名內(nèi)部類,而不能用lambda表達式

JavaEE & 線程案例 & 定時器 & 線程池 and 工廠模式

  • 寫法
public static void main(String[] args) {
    Timer timer = new Timer();
    timer.schedule(new TimerTask() {
        @Override
        public void run() {
            for (int i = 0; i < 10; i++) {
                System.out.println("好耶 ^ v ^");
            }
        }
    },1000);
    System.out.println("不好耶 T . T");
}

JavaEE & 線程案例 & 定時器 & 線程池 and 工廠模式

  • TimerTask實現(xiàn)了Runnable

    • 不能傳Runnable對象過去,這屬于向下轉(zhuǎn)型~
  • JavaEE & 線程案例 & 定時器 & 線程池 and 工廠模式

    • 是Runnable的一個“封裝”
    • 所以,重寫run方法,合情合理~
    • 只不過不能用
  • 而在Timer的schedule方法內(nèi)部,則將這個線程保存起來,定時后執(zhí)行~

JavaEE & 線程案例 & 定時器 & 線程池 and 工廠模式

  • 而這,有一個細節(jié),就是執(zhí)行完后,程序并沒有結(jié)束,進程并沒退出

原因是:

  • Timer內(nèi)置了一個前臺線程
    • 阻止進程退出~
    • 這并不是重點,其實就是timer在等待被安排下一個任務(wù)~
1.1.2 定時器管理多個線程
public class Test {

    public static void main(String[] args) {
        Timer timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println("星期一好耶 ^ v ^");
            }
        },1000);
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println("星期二好耶 ^ v ^");
            }
        },2000);
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println("星期三好耶 ^ v ^");
            }
        },3000);
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println("星期四好耶 ^ v ^");
            }
        },4000);
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println("星期五好耶 ^ v ^");
            }
        },5000);
        System.out.println("今天不好耶 T . T");
    }

}
  • 那么就安排多個任務(wù)唄~

JavaEE & 線程案例 & 定時器 & 線程池 and 工廠模式

JavaEE & 線程案例 & 定時器 & 線程池 and 工廠模式

1.1.3 定時器的使用場景
  • 應(yīng)用場景特別多

    • 尤其是網(wǎng)絡(luò)編程
  • 而這個任務(wù)等待,不應(yīng)該是無期限的

    • 超時:504 【gateway timeout】
  • 定時器可以強制終止請求:瀏覽器內(nèi)部都有一個定時器,發(fā)送請求后,定時器就開始定時;若在規(guī)定時間內(nèi),響應(yīng)數(shù)據(jù)沒有返回,就會強制終止請求
    JavaEE & 線程案例 & 定時器 & 線程池 and 工廠模式

  • 這個方法一般在任務(wù)的run方法中調(diào)用,確定是否及時

    • 這種特殊語法不是我們能理解的,并且目前我們不需要用到這個用法~

1.2 自己實現(xiàn)一個定時器

  • 想法一,根據(jù)任務(wù)們的時間
    • 在添入的時候,就讓他們啟動并以對應(yīng)的時間"睡下"
      • 有點像睡眠排序法這個消遣的笑話~
    • 顯然這個方法是不科學(xué)的,線程到達一個量級,進程必然裝不下
    • 系統(tǒng)必然卡死崩掉
  • 想法二,根據(jù)時間,到了時間自動啟動~
    • 將任務(wù)們按照時間長短排序
    • 每次只看最早啟動的任務(wù)就好
      • 當(dāng)然,等待時間是同步的~
      • 每個任務(wù)都有在等
    • 啟動,再去看接下來的任務(wù)~
      • 如果兩個任務(wù)同時啟動,順序則不能確定~

是不是觸動你的DNA了?

  • 沒錯,搞一個堆就好了
    • 每次可見堆頂元素~
    • 而小根堆堆頂正是我們這里的最早啟動的任務(wù)~
    • 舊堆頂取走后,新堆頂又是剩余的最早啟動的任務(wù)~
  • 而定時器的核心數(shù)據(jù)結(jié)構(gòu)就是:優(yōu)先級隊列 ===> 堆
    • 而定時器可能被多線程使用,所以線程安全問題也要被保證
    • 隊列為空,隊列為“滿”的時候,對操作也要有限制(不應(yīng)該有無限個任務(wù))
    • 這就需要我們的阻塞隊列~

即,定時器底層就是一個阻塞優(yōu)先級隊列! ===> PriorityBlockingQueue

  • 對于PriorityBlockingQueue,我這里并不會去模擬~
1.2.1 屬性
class MyTask {
    public Runnable runnable;
    public long time;
}
public class MyTimer {
    private PriorityBlockingQueue<MyTask> tasks = new PriorityBlockingQueue<>();
    
}

阻塞優(yōu)先級隊列中的元素應(yīng)該有如下兩個信息:

  • MyTask
  1. 執(zhí)行什么任務(wù)~
  2. 任務(wù)什么時候執(zhí)行~

JavaEE & 線程案例 & 定時器 & 線程池 and 工廠模式

1.2.2 建立一個MyTask對象
  1. runnable就是一個任務(wù)~
  2. time是絕對時間,而不是定時時間
    • 是”啟動時間“的具體時間
    • 到達這個時間,任務(wù)才能運行~
    • 為1970.01.01那一天的00:00:00到構(gòu)建對象時的此時此刻的毫秒數(shù)~
  • 獲取當(dāng)前時間方法:System.currentTimeMillis()
class MyTask {
    public Runnable runnable;
    public long time;
    //絕對時間戳~
    //方便判斷~
    //這個不是定時時間

    public MyTask(Runnable runnable, long delay) {
        this.runnable = runnable;
        this.time = delay + System.currentTimeMillis();
    }
}
1.2.3 schedule方法
public void schedule(Runnable runnable, long delay) {
    MyTask myTask = new MyTask(runnable, delay);
    tasks.put(myTask);
}
  • 構(gòu)造一個myTask對象插入到隊列中~
1.2.4 構(gòu)造方法初步設(shè)計
public MyTimer() {
        Thread t = new Thread(() -> {
            try {
                MyTask myTask = tasks.take();
                long nowTime = System.currentTimeMillis();
                if(myTask.time <= nowTime) {
                    //啟動
                }else {
                    //不能啟動
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
    }
}
  • 定時器被構(gòu)造出來后,應(yīng)該就已經(jīng)啟動“母線程”
    • 就應(yīng)該嘗試【take】了
    • 只不過隊列為空,要阻塞等待~
  • 之后通過schedule安排任務(wù)~【put】

JavaEE & 線程案例 & 定時器 & 線程池 and 工廠模式

  • 啟動:
    • 調(diào)用run方法
  • 不能啟動:
    • 將任務(wù)返回隊列
1.2.5 構(gòu)造方法最終設(shè)計
  • 在構(gòu)造方法初步設(shè)計有兩個很嚴重的BUG
    • 可以停止觀看去想一想~
  1. 優(yōu)先級對于自定義類,需要我們給“比較規(guī)則”,“優(yōu)先級規(guī)則”
  2. “沒有等待”以及“盲目等待”

對于1. 比較規(guī)則:

  • 只需要讓MyTask實現(xiàn)比較接口

  • 當(dāng)然也可以傳比較器~(lambda表達式)

JavaEE & 線程案例 & 定時器 & 線程池 and 工廠模式

  • 兩種方式都OK~

  • 左減右大于0

    • 如果代表此對象大于該對象代表升序排列 ===> 小根堆

    • 如果代表此對象小于該對象代表降序排列 ===> 大根堆

對于2. “沒有等待”以及“盲目等待”

  • 上述代碼只會判斷一次~
    • 應(yīng)該套上一個循環(huán)~

JavaEE & 線程案例 & 定時器 & 線程池 and 工廠模式

  • wait等待,喚醒起來比較方便安全

    • sleep不是一個很好的選擇~
    • 因為新任務(wù)的插入,要進行喚醒
    • 超過限定時間,自動醒來
      • wait需要有鎖,這里我把循環(huán)體整個框起來了
      • 我用的是“同步鎖”
  • “盲目等待” 代表,這里放回去后,計算器又會判斷是否可啟動

    • 這樣就會導(dǎo)致一段時間內(nèi),這個任務(wù)反復(fù)被拿來拿去無數(shù)次~
    • 相當(dāng)于,上課時看表,一秒看一次,忙等
    • 而計算機,1ms就可以看很多很多次~
  • 那么我們只需要在schedule時喚醒一下,讓他才判斷一次就行了~

    • 這防止新插入的任務(wù)更早而被忽略
  • 大大減少判斷次數(shù)!

JavaEE & 線程案例 & 定時器 & 線程池 and 工廠模式

  • 最終版:
public void schedule(Runnable runnable, long delay) {
    MyTask myTask = new MyTask(runnable, delay);
    tasks.put(myTask);
    synchronized (locker) {
        locker.notify();
    }
}

private Object locker = new Object();

public MyTimer() {
    Thread t = new Thread(() -> {
        while(true) {
            synchronized (locker) {
                try {
                    MyTask myTask = tasks.take();
                    long nowTime = System.currentTimeMillis();
                    if(myTask.time <= nowTime) {
                        myTask.runnable.run();
                    }else {
                        tasks.put(myTask);
                        locker.wait(myTask.time - nowTime);
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    });
    t.start();
}

JavaEE & 線程案例 & 定時器 & 線程池 and 工廠模式

  • 別忘了啟動線程~

1.3 測試MyTimer

  • 用MyTimer替換之前的Timer

  • TimeTask也可替換為Runnable,不過沒關(guān)系,向上轉(zhuǎn)型~

public static void main(String[] args) {
    MyTimer timer = new MyTimer();
    timer.schedule(new TimerTask() {
        @Override
        public void run() {
            System.out.println("星期一好耶 ^ v ^");
        }
    },1000);
    timer.schedule(new TimerTask() {
        @Override
        public void run() {
            System.out.println("星期二好耶 ^ v ^");
        }
    },2000);
    timer.schedule(new TimerTask() {
        @Override
        public void run() {
            System.out.println("星期三好耶 ^ v ^");
        }
    },3000);
    timer.schedule(new TimerTask() {
        @Override
        public void run() {
            System.out.println("星期四好耶 ^ v ^");
        }
    },4000);
    timer.schedule(new TimerTask() {
        @Override
        public void run() {
            System.out.println("星期五好耶 ^ v ^");
        }
    },5000);
    System.out.println("今天不好耶 T . T");
}
  • 測試結(jié)果正常:

JavaEE & 線程案例 & 定時器 & 線程池 and 工廠模式

  • 退出代碼130,是按ctrl + f2

1.4 補充

  • 你可能也發(fā)現(xiàn)了,代碼之中并沒有完全保證,一個線程一定會在規(guī)定的時間后執(zhí)行
  • 因為一個定時器,只能運行一個線程,沒有并發(fā)性
    • 只是和main線程并發(fā)~
    • 所以,如果一個線程運行時間較長,會導(dǎo)致其后的任務(wù)“被迫延時”
    • 而判斷條件不是等于等于,也有這一方面原因
      • 另一方面原因是,可能因為調(diào)度問題有誤差~

JavaEE & 線程案例 & 定時器 & 線程池 and 工廠模式

  • 此時這個定時器,就只能起到,保證任務(wù)執(zhí)行順序的功能~
1.4.1 例子1
  • 例如以下測試代碼:
 public static void main(String[] args) {
        MyTimer timer = new MyTimer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println("星期一好耶 ^ v ^");
                try {
                    Thread.sleep(5000);
                    System.out.println("已過去五秒");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },1000);
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println("星期二好耶 ^ v ^");
            }
        },2000);
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println("星期三好耶 ^ v ^");
            }
        },3000);
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println("星期四好耶 ^ v ^");
            }
        },4000);
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println("星期五好耶 ^ v ^");
            }
        },5000);
        System.out.println("今天不好耶 T . T");
    }
}

JavaEE & 線程案例 & 定時器 & 線程池 and 工廠模式

  • 第一個任務(wù)要花5秒,而還差1秒,第二個任務(wù)就應(yīng)該啟動~
  • 而現(xiàn)象是這樣的:

JavaEE & 線程案例 & 定時器 & 線程池 and 工廠模式

  • 后面的任務(wù)已經(jīng)受嚴重延遲~
1.4.2 例子2
  • 如果一個任務(wù)死循環(huán)了,會導(dǎo)致后面的任務(wù)無限延期

JavaEE & 線程案例 & 定時器 & 線程池 and 工廠模式

  • 就會導(dǎo)致下面這種情況:

JavaEE & 線程案例 & 定時器 & 線程池 and 工廠模式

注意:

  • 這并不是我寫的定時器有問題 ,Java標準庫的定時器,就是這樣子的, 一個定時器一個時間段里只能執(zhí)行一個任務(wù)
    • 現(xiàn)象跟MyTimer是一樣的
    • 就是這兩個例子那樣
  • 一個任務(wù)時間太長,會導(dǎo)致下一個任務(wù)延遲
  • 只起“區(qū)分先后”的作用

1.5 順帶一題

問:wait的同步鎖的位置不同,結(jié)果會怎么樣?

  • 例如:

JavaEE & 線程案例 & 定時器 & 線程池 and 工廠模式

  • 這兩種鎖的框法不同,結(jié)果一樣嗎?
1.5.1 后者

JavaEE & 線程案例 & 定時器 & 線程池 and 工廠模式

  • 重點就在于,沒有保證take與wait是原子的~
1.5.2 前者
  • 保證原子性后:

JavaEE & 線程案例 & 定時器 & 線程池 and 工廠模式

2. 線程池

  • 跟字符串常量池和數(shù)據(jù)庫連接池一樣
    • 這個池的作用就提高效率,節(jié)省開銷~
    • 即使線程很輕量,但是積少成多就不能忽略~
  • 只要再池子里去拿,就要比從系統(tǒng)申請要快~

提高效率還能提高輕量化線程“協(xié)程”,Java標準庫還不支持

而線程池是一個重要的途徑~

  • 從線程池里拿線程,純純的用戶態(tài)操作
  • 而從系統(tǒng)上申請,就必須設(shè)計用戶態(tài)和內(nèi)核態(tài)之間的切換
    • 真正的創(chuàng)建線程,是在內(nèi)核態(tài)完成的

2.1 用戶態(tài)和內(nèi)核態(tài)

  • 操作系統(tǒng) = 內(nèi)核 + 配套的應(yīng)用程序
    • 內(nèi)核:各種系統(tǒng)管理和驅(qū)動,而內(nèi)核就是為了支持應(yīng)用程序的
    • 這里不僅僅指核心~
      • 因為進程管理這是他的工作之一
      • 邏輯核心們也只是他的打工人~

JavaEE & 線程案例 & 定時器 & 線程池 and 工廠模式

  • 需要內(nèi)核支持,才能運行的應(yīng)用程序~

    • 例如,println,打印到屏幕,需要通過硬件管理~
  • 即,內(nèi)核給那么多人服務(wù),那么就不一定及時

舉個栗子:

  • 去銀行打印資料,前臺可以幫你打印
    • 而前臺在同時會去幫助其他人,給你打印好了還要好一會兒才給你~

JavaEE & 線程案例 & 定時器 & 線程池 and 工廠模式

  • 你也可以去自助打印機打印
    • 這樣的時間消耗就只會縮短在 “打印需求” 內(nèi)去消耗

JavaEE & 線程案例 & 定時器 & 線程池 and 工廠模式

  • 也就是說,我們在申請線程時

    • 內(nèi)核態(tài)申請 ==> 內(nèi)核要顧及進程管理和其他管理與驅(qū)動~

    • JavaEE & 線程案例 & 定時器 & 線程池 and 工廠模式

    • 用戶態(tài)去拿 ==> 只需要在進程管理這個單項里去拿線程~

    • JavaEE & 線程案例 & 定時器 & 線程池 and 工廠模式

  • 當(dāng)然,線程的誕生,還是要內(nèi)核態(tài)申請

    • 放進線程池,之后在線程池里用戶態(tài)拿就好~

2.2 標準庫線程池類ExecutorService

  • Java標準庫實現(xiàn)了一個接口,ExecutorService,在進程中服務(wù)線程執(zhí)行~

    • 通過這個池的服務(wù),不需要每次都申請~
  • 但是這個接口不是通過new子類對象去實例化的,而是用一個靜態(tài)方法去實例化~

JavaEE & 線程案例 & 定時器 & 線程池 and 工廠模式

  • 而這里的Executors類就是“工廠類”
    • 這個類就是為了構(gòu)造“線程池”而存在的
    • 這個類可以調(diào)用各種靜態(tài)方法
      • 而這些靜態(tài)方法使用起來簡單
      • 并且可以構(gòu)造各種滿足我們特殊需要的對象

2.3 工廠模式

  • “工廠”

    • 即“對象工廠”,可以工廠生產(chǎn)出不同的對象
    • 有員工去幫你生產(chǎn),使用簡單
      • 降低使用成本
    • 相同原料可以有不同產(chǎn)品,避免參數(shù)列表相同導(dǎo)致無法觸發(fā)重載
      • 重要作用!
  • 而工廠模式其實就是,把一個類/接口的構(gòu)造方法,交給一個“工廠類”去定義

    • 即,將構(gòu)造方法打包成類

Executors工廠

JavaEE & 線程案例 & 定時器 & 線程池 and 工廠模式

  • 重點掌握

JavaEE & 線程案例 & 定時器 & 線程池 and 工廠模式

你也可以自己“開個廠”

  • 就比如說,一個【堆】,泛型類是我們的自定義類
  • 而我們的自定義類要我們?nèi)ヒ?guī)定比較方法
public class A {
    int a1;
    int a2;
    int a3;
    int a4;
    int a5;
    int a6;
}
  • 假設(shè)我們A類有六個成員(都是int類型)
    • 要求建立6個堆,每個堆以不同的比較規(guī)則去創(chuàng)建
      • 每次創(chuàng)建都好麻煩,都要寫個比較器~
  • 只需要“開個比較器廠”,把這些構(gòu)造方法包裝起來就好~
    • 以后構(gòu)造的時候,通過不同的方法名調(diào)用對應(yīng)的構(gòu)造方法~
    • 比較器Comparator
      • 構(gòu)造方法基本都沒有參數(shù)列表的,那么就不能用重載去解決~
        • 比較器的不同主要不是因為構(gòu)造方法,而是compare被怎么重寫有關(guān)~
      • compare方法重寫也只能重寫一個

JavaEE & 線程案例 & 定時器 & 線程池 and 工廠模式

2.3.1 開[A的構(gòu)造廠]
    public static A createA1(int a) {
        //匿名內(nèi)部類優(yōu)先捕獲全局性質(zhì)變量,這里在代碼塊內(nèi),a1就為全局性變量~
        return new A() {
            {
                this.a1 = a;
            }
        };
    }
    public static A createA2(int a) {
        return new A() {
            {
                this.a2 = a;
            }
        };
    }
    public static A createA3(int a) {
        return new A() {
            {
                this.a3 = a;
            }
        };
    }
    public static A createA4(int a) {
        return new A() {
            {
                this.a4 = a;
            }
        };
    }
    public static A createA5(int a) {
        return new A() {
            {
                this.a5 = a;
            }
        };
    }
    public static A createA6(int a) {
        return new A() {
            {
                this.a6 = a;
            }
        };
    }
}

JavaEE & 線程案例 & 定時器 & 線程池 and 工廠模式

2.3.2 開[A的比較器廠]
class CreateComparatorA {
    public static Comparator<A> createA1() {
        return ((o1, o2) -> {
           return o1.a1 - o2.a1;
        });
    }
    public static Comparator<A> createA2() {
        return ((o1, o2) -> {
           return o1.a2 - o2.a2;
        });
    }
    public static Comparator<A> createA3() {
        return ((o1, o2) -> {
           return o1.a3 - o2.a3;
        });
    }
    public static Comparator<A> createA4() {
        return ((o1, o2) -> {
           return o1.a4 - o2.a4;
        });
    }
    public static Comparator<A> createA5() {
        return ((o1, o2) -> {
           return o1.a5 - o2.a5;
        });
    }
    public static Comparator<A> createA6() {
        return ((o1, o2) -> {
           return o1.a6 - o2.a6;
        });
    }
}

JavaEE & 線程案例 & 定時器 & 線程池 and 工廠模式

2.3.3 測試
public class A {
    int a1;
    int a2;
    int a3;
    int a4;
    int a5;
    int a6;
    //參數(shù)列表相同無法特定構(gòu)造特定成員~

    @Override
    public String toString() {
        return "A{" +
                "a1=" + a1 +
                ", a2=" + a2 +
                ", a3=" + a3 +
                ", a4=" + a4 +
                ", a5=" + a5 +
                ", a6=" + a6 +
                '}' + '\n';
    }

    public static void main(String[] args) {
        PriorityQueue<A> queue1 = new PriorityQueue<>(CreateComparatorA.createA1());
        PriorityQueue<A> queue2 = new PriorityQueue<>(CreateComparatorA.createA2());
        PriorityQueue<A> queue3 = new PriorityQueue<>(CreateComparatorA.createA3());
        PriorityQueue<A> queue4 = new PriorityQueue<>(CreateComparatorA.createA4());
        PriorityQueue<A> queue5 = new PriorityQueue<>(CreateComparatorA.createA5());
        PriorityQueue<A> queue6 = new PriorityQueue<>(CreateComparatorA.createA6());

        queue1.offer(createA.createA1(2));
        queue1.offer(createA.createA1(1));
        queue1.offer(createA.createA1(4));
        queue1.offer(createA.createA1(3));
        queue1.offer(createA.createA1(5));

        System.out.println(queue1);

    }
}
  • 結(jié)果:
    • 確實以a1為標準~

JavaEE & 線程案例 & 定時器 & 線程池 and 工廠模式

當(dāng)然,工廠當(dāng)然不只可以生產(chǎn)構(gòu)造方法:

  • 還能生產(chǎn)那些我們需要的:重復(fù)參數(shù)列表的方法
  • 例如生產(chǎn)A的toString()方法~
  • 不額外說了~

2.4 ExecutorService的屬性和方法

2.4.1 通過工廠類構(gòu)造

JavaEE & 線程案例 & 定時器 & 線程池 and 工廠模式

  • 不給固定容量,按需創(chuàng)建線程池~

JavaEE & 線程案例 & 定時器 & 線程池 and 工廠模式

  • 跟定時器有關(guān)~

最重點的一個:

JavaEE & 線程案例 & 定時器 & 線程池 and 工廠模式

  • 提供固定容量的線程池構(gòu)造方法~

JavaEE & 線程案例 & 定時器 & 線程池 and 工廠模式

2.4.2 submit方法
  • 提交線程~
public static void main(String[] args) {
    ExecutorService pool = Executors.newFixedThreadPool(10);
    pool.submit(() -> {
        System.out.println("好耶 ^ v ^ ");
    });
}
2.4.3 ThreadPoolExecutor類的屬性
  • 既然是構(gòu)造ThreadPoolExecutor
  • 那么它的屬性就至關(guān)重要~

下面是Java的官方文檔的內(nèi)容:

JavaEE & 線程案例 & 定時器 & 線程池 and 工廠模式

  • 這個類在【util應(yīng)用應(yīng)用工具】的【concurrent并發(fā)包】中~
    • 簡稱【JUC

JavaEE & 線程案例 & 定時器 & 線程池 and 工廠模式

  • 通過這個構(gòu)造方法讓我們看到很多屬性~
    • 我也只講解這幾個屬性~
    • 也不講這個方法咋實現(xiàn)的
  1. corePoolSizemaximumPoolSize
  • corePoolSize為核心線程數(shù)
  • maximumPoolSize為最大線程數(shù)
    • 核心線程,即不能隨意停止的線程
    • 最大線程數(shù)里【包含核心線程和“臨時線程”】
      • 這個“臨時線程”就相當(dāng)于公司里的實習(xí)生
        • 關(guān)鍵時期來應(yīng)急
      • 這個核心線程就相當(dāng)于正式員工
        • 不能隨意辭退

線程池會在任務(wù)少的空閑期,根據(jù)這些參數(shù)進行線程調(diào)整,把一些臨時線程給銷毀了~

  1. keepAliveTime(long)unit(TimeUnit)
  • keepAliveTime 為臨時線程存活時間~

    • “實習(xí)生”并不是立即被辭退
    • 而是跟這個參數(shù)有關(guān)
    • 允許最多活多久~
  • unit ==> 時間單位

  1. BlockingQueue< Runnable > workQueue
  • 線程池要管理很多任務(wù)
  • 通過阻塞隊列來組織~
    • 方便程序員控制線程數(shù)據(jù)交互
    • submit提交到這個阻塞隊列里~
  1. ThreadFactory threadFactory
  • 線程工廠 ,跟工廠模式有關(guān)~
  • 不細講
  1. RejectedExecutionHandler handler
  • 線程池的拒絕執(zhí)行應(yīng)對策略~
  • 池子滿了,繼續(xù)往里添加線程,如何應(yīng)對?如何拒絕?
    • 線程池滿了是不依賴阻塞隊列的
      • 這個任務(wù)要不要干最好立馬給出決策!
    • 一般是空了依賴阻塞隊列~
    • 還有阻塞隊列的線程安全性和解耦合性也很好
2.4.4 線程池的拒絕策略

JavaEE & 線程案例 & 定時器 & 線程池 and 工廠模式

  1. 直接拋異常 ---- 毀滅
    • 哇哇大哭
  2. 直接拒絕 ---- 誰給我這個線程任務(wù),誰自己去完成
    • 達咩達咩
  3. 拋棄最老任務(wù) ---- 把最先安排的任務(wù) [隊列頭] 給刪了,替換成新任務(wù)
    • 做出犧牲
  4. 拋棄最新任務(wù) ---- 我繼續(xù)干原來的活,新的活誰都沒干
    • 原封不動

2.5 模擬實現(xiàn)線程池

public class MyThreadPool {
    private BlockingQueue<Runnable> pool = new LinkedBlockingQueue<>();

    public void submit(Runnable runnable) throws InterruptedException {
        pool.put(runnable);
    }

    //實現(xiàn)固定線程數(shù)的線程池
    //不是容量,是確確實實的線程數(shù)
    
    public MyThreadPool(int number) {
        for (int i = 0; i < number; i++) {
            Thread thread = new Thread(() -> {
                Runnable runnable = null;
                try {
                    while(true) {
                    	runnable = pool.take();
                    	runnable.run();  
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
            thread.start();
        }
    }
}
  • 我們的簡單實現(xiàn),不涉及2.4.3的屬性~

  • 注意:這里的線程數(shù),是工作人數(shù),定量

    • 而阻塞隊列里的線程數(shù),則是這些人做的”任務(wù)“

JavaEE & 線程案例 & 定時器 & 線程池 and 工廠模式

  • 測試:
public static void main(String[] args) throws InterruptedException {
    MyThreadPool myThreadPool = new MyThreadPool(10);
    for (int i = 1; i <= 1000; i++) {
        int id = i; //線程id,變量捕獲~
        myThreadPool.submit(() -> {
            System.out.println("好耶^ v ^ " + id);
        });
    }
  • 提供固定的工作人員 * 10
  • 源源不斷塞1000個任務(wù)~
  • 工作人員瘋搶~

JavaEE & 線程案例 & 定時器 & 線程池 and 工廠模式
——

  • 數(shù)據(jù)順序無序很正常
    • 線程調(diào)度無序嘛~
  • 程序還未結(jié)束
    • 這是因為十個工作人員“吸血鬼”還等著任務(wù)呢~

線程池中如何體現(xiàn),“用戶態(tài)拿”:

  1. 線程池中有固定數(shù)量的線程,而這些線程是一開始一次性申請的
  2. 之后我們無需為了一個或者多個任務(wù)再去額外申請一個Thread對象了
  3. 只需要提交任務(wù)給線程池,讓線程池里的“空線程”去幫我們干事
  4. 反復(fù)用這些空線程去做任務(wù)~
    • 只需要提交就行,不需要從線程池里取線程
    • 我們可能沒有拿線程這個操作~
    • 但是這樣就相當(dāng)于我們拿了線程做了任務(wù)~
      • 只不過這個任務(wù)幾乎全自動地被線程池幫忙在一個線程里執(zhí)行了
      • 而原本執(zhí)行一個任務(wù)就要我們需要自己申請個新的Thread對象
        JavaEE & 線程案例 & 定時器 & 線程池 and 工廠模式

注意:

  • 線程 不等于 任務(wù)
  • 任務(wù)必須依托線程才能執(zhí)行
    ——

2.6 線程池的固定線程數(shù)的確定(理論)

  • 至于線程池固定線程數(shù),設(shè)置為多少合適?

    • 最好最科學(xué)的方式就是去測試!
  • cpu密集型,主要做一些計算工作,要在cpu上運行~

  • IO密集型,主要等待一些IO操作(讀寫硬盤/讀寫網(wǎng)卡),不怎么吃cpu

    • 如果你的線程全是使用cpu的,那就得設(shè)置線程數(shù)少于核心數(shù)~
    • 如果全是使用IO的,那就可以設(shè)置很多很多線程,遠超核心數(shù)
  • 而實際情況不會這么極端,所以這個線程數(shù)一定是要看實際情況的

    • 所以就要測試!
    • 通過一些數(shù)據(jù)去看看哪個固定線程數(shù)是OK的
      • 例如執(zhí)行時間…檢測資源使用狀態(tài)~
      • 控制變量法~


文章到此結(jié)束!謝謝觀看 !
可以叫我 小馬,我可能寫的不好或者有錯誤,但是一起加油鴨??!

多線程初階已經(jīng)結(jié)束~ 后續(xù)會出線程進階的博客!

敬請期待吧~文章來源地址http://www.zghlxwxcb.cn/news/detail-417818.html



到了這里,關(guān)于JavaEE & 線程案例 & 定時器 & 線程池 and 工廠模式的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

  • 【JavaEE初階】多線程(四)阻塞隊列 定時器 線程池

    【JavaEE初階】多線程(四)阻塞隊列 定時器 線程池

    概念 阻塞隊列是一種特殊的隊列. 也遵守 “ 先進先出 ” 的原則. 阻塞隊列能是一種線程安全的數(shù)據(jù)結(jié)構(gòu), 并且具有以下特性: 當(dāng)隊列滿的時候, 繼續(xù)入隊列就會阻塞, 直到有其他線程從隊列中取走元素. 當(dāng)隊列空的時候, 繼續(xù)出隊列也會阻塞,直到有其他線程往隊列中插入元素

    2023年04月26日
    瀏覽(19)
  • 多線程案例(3)-定時器

    大家好,我是曉星航。今天為大家?guī)淼氖?多線程案例三 相關(guān)的講解!?? 定時器是什么 定時器也是軟件開發(fā)中的一個重要組件. 類似于一個 “鬧鐘”. 達到一個設(shè)定的時間之后, 就執(zhí)行某個指定 好的代碼. 定時器是一種實際開發(fā)中非常常用的組件. 比如網(wǎng)絡(luò)通信中, 如果對方

    2024年02月14日
    瀏覽(17)
  • Java多線程案例之定時器

    Java多線程案例之定時器

    定時器是一種實際開發(fā)中非常常用的組件, 類似于一個 “鬧鐘”, 達到一個設(shè)定的時間之后, 就執(zhí)行某個指定好的代碼. 比如網(wǎng)絡(luò)通信中, 如果對方 500ms 內(nèi)沒有返回數(shù)據(jù), 則斷開連接嘗試重連. 比如一個 Map, 希望里面的某個 key 在 3s 之后過期(自動刪除). 類似于這樣的場景就需要

    2024年02月20日
    瀏覽(25)
  • 【Java | 多線程案例】定時器的實現(xiàn)

    【Java | 多線程案例】定時器的實現(xiàn)

    個人主頁:兜里有顆棉花糖 歡迎 點贊?? 收藏? 留言? 加關(guān)注??本文由 兜里有顆棉花糖 原創(chuàng) 收錄于專欄【Java系列專欄】【JaveEE學(xué)習(xí)專欄】 本專欄旨在分享學(xué)習(xí)JavaEE的一點學(xué)習(xí)心得,歡迎大家在評論區(qū)交流討論?? Java中, Timer類 是用于計劃和執(zhí)行重復(fù)任務(wù)的類( Java標準

    2024年02月03日
    瀏覽(15)
  • Java 多線程系列Ⅳ(單例模式+阻塞式隊列+定時器+線程池)

    Java 多線程系列Ⅳ(單例模式+阻塞式隊列+定時器+線程池)

    設(shè)計模式就是軟件開發(fā)中的“棋譜”,軟件開發(fā)中也有很多常見的 “問題場景”。針對這些問題場景,大佬們總結(jié)出了一些固定的套路。按照這些套路來實現(xiàn)代碼可能不會很好,但至少不會很差。當(dāng)前階段我們需要掌握兩種設(shè)計模式: (1)單例模式 (2)工廠模式 概念/特征

    2024年02月09日
    瀏覽(25)
  • 【JavaEE初階】 定時器詳解與實現(xiàn)

    【JavaEE初階】 定時器詳解與實現(xiàn)

    定時器也是軟件開發(fā)中的一個重要組件. 類似于一個 “鬧鐘”. 達到一個設(shè)定的時間之后, 就執(zhí)行某個指定好的代碼 定時器是一種實際開發(fā)中非常常用的組件. 比如網(wǎng)絡(luò)通信中, 如果對方 500ms 內(nèi)沒有返回數(shù)據(jù), 則斷開連接嘗試重連. 比如一個 Map, 希望里面的某個 key 在 3s 之后過

    2024年02月06日
    瀏覽(20)
  • 【多線程】定時器,詳解定時器原理,讓大家更深刻的理解多線程

    【多線程】定時器,詳解定時器原理,讓大家更深刻的理解多線程

    前言: 大家好,我是 良辰丫 ,今天我們一起了解一下定時器,通過定時器來熟悉一下線程安全等相關(guān)知識點.?????? ??個人主頁:良辰針不戳 ??所屬專欄:javaEE初階 ??勵志語句:生活也許會讓我們遍體鱗傷,但最終這些傷口會成為我們一輩子的財富。 ??期待大家三連,關(guān)注

    2024年02月01日
    瀏覽(27)
  • 多線程---定時器

    定時器的功能和“鬧鐘”類似,代碼中的定時器通常都是“多長時間之后,執(zhí)行某個動作”。 注: 一個定時器可以安排多個任務(wù)。 調(diào)用schedule安排任務(wù)時,一定要重寫run方法,明確任務(wù)內(nèi)容 定時器開啟后不會自動結(jié)束,得手動殺死進程 版本一:實現(xiàn)簡單的定時器 schedule方法

    2024年02月08日
    瀏覽(24)
  • java多線程之定時器

    java多線程之定時器

    定時功能在java中主要是通過 Timer 類實現(xiàn),因為它在內(nèi)部還是使用多線程的方式進行處理,所以和多線程技術(shù)還是有非常大的管理 在JDK庫中Timer類主要負責(zé)計劃任務(wù)的功能,也就是在指定時間開始執(zhí)行某一個任務(wù),Timer類的主要功能就是設(shè)置計劃任務(wù),封裝任務(wù)的類確是Timer

    2024年02月05日
    瀏覽(27)
  • 51-定時器與按鍵控制LED流水燈模式&定時器時鐘

    51-定時器與按鍵控制LED流水燈模式&定時器時鐘

    按鍵(以獨立按鍵為例)控制LED流水燈模式: 在按鍵控制LED流水燈模式中,如果僅僅簡單的把獨立按鍵與LED流水燈拼接起來,則會出現(xiàn)一些問題:在LED流水燈的代碼中會有長時間的Delay,此時按鍵檢測就會很不靈敏:按下時不靈敏,需要一些時間才能被檢測到,按下后再松手時

    2024年02月08日
    瀏覽(19)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包