手機網(wǎng)站建設軟件營銷型網(wǎng)站重要特點是
目錄
什么是設計模式?
單例模式
餓漢模式
懶漢模式
工廠模式
線程池
線程池種類
ThreadPoolExcutor的構造方法:
手動實現(xiàn)一個線程池?
什么是設計模式?
計算機行業(yè)程序員水平層次不齊,為了讓所有人都能夠寫出規(guī)范的代碼,于是就有了設計模式,針對一些典型的場景,給出一些典型的解決方案
單例模式
單例模式 ==> 單個實例(對象)
在一些場景中,有的特定類只能創(chuàng)建一個實例,不能創(chuàng)建多個實例
使用了單例模式后,此時就不能創(chuàng)建多個實例了,我們想創(chuàng)建多個實例都難,單例模式就是針對上述的需求場景進行了更強制的保證,通過巧用java的語法,達成某個類 只能被創(chuàng)建出一個實例這樣的效果(當程序員不小心創(chuàng)建了多個實例,就會報錯)
單例模式實現(xiàn)
餓漢模式
// 餓漢模式的 單例模式 實現(xiàn)
// 此處保證 Singleton 這個類只能創(chuàng)建出一個實例
class Singleton{// 在此處,先把實例給創(chuàng)建出來private static Singleton instance = new Singleton();// 如果需要使用 instance,通過統(tǒng)一的Singleton.getInstance() 方式獲取public static Singleton getInstance(){return instance;}// 為了避免 Singleton 類不小心被復制多份// 把構造方法設為 private,在類外面,就無法通過new 的方式來創(chuàng)建這個 Singleton了private Singleton(){};
}
public class Thread3 {public static void main(String[] args) {Singleton s = Singleton.getInstance();Singleton s2 = Singleton.getInstance();System.out.println(s==s2);Singleton s3 = new Singleton(); // 報錯,原因是Singleton的構造方法被private修飾,因此無法通過new的方式創(chuàng)建Singleton對象}
}
懶漢模式
class Singleton2{ private static volatile Singleton2 instance = null; //使用volatile表示instance是個易變的public static Singleton2 getInstance(){if (instance==null) { // 此處負責判斷是否要加鎖synchronized (Singleton2.class) {if(instance==null){ // 此處判斷是否要創(chuàng)建對象instance = new Singleton2();}}}return instance;}private Singleton2(){};
}
懶漢模式下,有創(chuàng)建Singleton對象的操作(寫操作),所以可能會出現(xiàn)線程安全問題,因此我們要進行加鎖操作,并標注instance是一個易變的對象(避免內(nèi)存可見性問題,和指令重排序問題)
工廠模式
工廠模式: 使用普通的方法,來代替構造方法,創(chuàng)建對象.? 在java中,構造方法存在一定缺陷,構造方法要求構造名必須為類名(方法名相同),構造參數(shù)可以不同,沒用返回值.如果我們只構造一種對象可以忽略這個缺陷,如果構造多種不同的情況的對象可能會出現(xiàn)問題,比如想要實現(xiàn)倆個不同的構造方法,但是它們的參數(shù)類型恰好都相同,但表達的意義不同,這時java就無法區(qū)分了.為了解決這個問題,就可以使用工程模式
比如分別使用笛卡爾坐標系和極坐標系表示坐標
import java.awt.*;
class PointFactory{public static Point makePointByXY(double x,double y){}public static Point makePointByRA(double r,double a){}
}
public class Thread6 {public static void main(String[] args) {Point p = PointFactory.makePointByXY(10,20);Point p2 = PointFactory.makePointByRA(10,30);}
}
線程池
線程存在的意義: 使用進程實現(xiàn)并發(fā)編程,"太重了",引入線程(輕量級進程),創(chuàng)建線程比創(chuàng)建線程更高效,銷毀線程比銷毀進程更高效,調(diào)度線程比調(diào)度進程更高效,此時使用多線程就可以在很多時候代替進程實現(xiàn)并發(fā)編程了
線程池存在的意義: 當我們需要頻繁創(chuàng)建銷毀線程的時候,就發(fā)現(xiàn)開銷也很大,想要進一步的提高效率,可以: 1.搞一個協(xié)程(輕量級線程) 2.使用線程池,事先把需要使用的線程創(chuàng)建好,放到池中,后面需要使用的時候,從池中獲取,如果用完了,再還給池.(創(chuàng)建線程和銷毀線程是交由操作系統(tǒng)內(nèi)核去完成的,從池子里獲取/還給池,是自己用戶代碼就能實現(xiàn)的,不必交給內(nèi)核操作)
public class Thread5 {public static void main(String[] args) {// 此處就構造了一個 10 個線程的線程池,就可以隨時安排這些線程干活了ExecutorService pool = Executors.newFixedThreadPool(10);// 當前往線程池中放了1000個任務,這1000個任務由線程池中的10個線程去執(zhí)行for (int i = 0;i < 1000;i++) {pool.submit(()->{System.out.println("hello");});}}
}
線程池提供了一個重要的方法,submit,可以給線程池提交若干個任務,這若干個任務可以由線程池中的線程去執(zhí)行完成..線程池中創(chuàng)建的線程是前臺線程,需要執(zhí)行完成后,主線程才可以結束.?
這里1000個任務相當于在一個隊列中,線程池中的這10個線程就依次取這個隊列中的任務,取一個就執(zhí)行一個,執(zhí)行完成后,再在這個隊列中取任務去執(zhí)行?
線程池種類
這些線程池,本質(zhì)上都是通過包裝 ThreadPoolExecutor 來實現(xiàn)的?
ThreadPoolExcutor的構造方法:
corePoolSize : 核心線程數(shù),
maximumPoolSize:? 最大線程數(shù),相當于線程池把線程分為倆大類,一類是核心線程,一類是非核心線程,最大線程數(shù)就是核心線程和非核心線程之和
一個程序有時任務多,有時任務少,如果任務多,我們就需要多一些線程,如果任務少,就需要線程盡量少,此時我們就可以保留核心線程,而淘汰掉一些非核心線程
實際開發(fā)中,線程池的線程數(shù)設定成多少合適?
程序分為CPU密集型,每個線程執(zhí)行的任務都需要狂轉CPU(進行一系列算術運算),此時線程池線程數(shù)最多不超過CPU核數(shù),因為cpu密集型要一直占用cpu,創(chuàng)建更多的線程也沒用
IO密集型,每個線程的工作就是等待IO(讀寫硬盤,讀寫網(wǎng)卡,等待用戶輸入),不占CPU,此時這樣的線程處于阻塞狀態(tài),不參與CPU調(diào)度,這個時候創(chuàng)建多個線程,不再受制于CPU核數(shù)了
實踐中確定線程數(shù),通過實驗的方式,康康設置幾個線程合適
long keepAliveTime: 非核心線程數(shù)不工作的最大時間,如果超過這個時間就銷毀
TimeUnit unit: 時間單位,ms,s,分鐘,小時......
BlockingQueue<Runnable> workQueue: 線程池的任務隊列
ThreadFactory threadFactory: 用于創(chuàng)建線程
RejectedExecutionHandler handler: 描述了線程池的"拒絕策略",是一個特殊的對象,描述了當線程池任務隊列滿了之后,如果繼續(xù)添加任務,線程池會有什么樣的行為,總共有以下4種策略
ThreadPoolExcutor.AbortPolicy: 如果任務隊列滿了,再新增任務,直接拋出異常
ThreadPoolExcutor.CallerRunsPoliy: 如果任務隊列滿了,多出來的任務,誰加的就由誰去執(zhí)行(交給調(diào)用者去執(zhí)行)
ThreadPoolExcutor.DisardOlderdestPolicy: 如果任務隊列滿了,就丟棄最老的任務
ThreadPoolExcutor.DiscardPolicy: 如果任務隊列滿了,就丟棄最新的任務
手動實現(xiàn)一個線程池?
一個線程池中至少有倆個部分,一個是阻塞隊列,用來保存任務,一個是若干個工作線程
class MyThreadPool{private BlockingQueue<Runnable> queue = new LinkedBlockingQueue<>();// n 表示線程數(shù)量public MyThreadPool(int n){// 創(chuàng)建 n 個線程for (int i = 0; i < n; i++) {Thread t = new Thread(()->{while (true){try {Runnable runnable = queue.take();runnable.run();} catch (InterruptedException e) {e.printStackTrace();}}});t.start();}}// 注冊任務交給線程池public void submit(Runnable runnable) {try {queue.put(runnable);} catch (InterruptedException e) {e.printStackTrace();}}
}