国产亚洲精品福利在线无卡一,国产精久久一区二区三区,亚洲精品无码国模,精品久久久久久无码专区不卡

當(dāng)前位置: 首頁(yè) > news >正文

手機(jī)網(wǎng)站模板開(kāi)發(fā)工具seo網(wǎng)絡(luò)營(yíng)銷推廣公司深圳

手機(jī)網(wǎng)站模板開(kāi)發(fā)工具,seo網(wǎng)絡(luò)營(yíng)銷推廣公司深圳,上海哪個(gè)公司做網(wǎng)站好,迅騰網(wǎng)絡(luò)網(wǎng)站建設(shè)有限公司文章目錄 單例模式什么是單例模式餓漢模式懶漢模式多線程- 懶漢模式分析多線程問(wèn)題第一種添加sychronized的方式第二種添加sychronized的方式改進(jìn)第二種添加sychronized的方式(DCL檢查鎖) 阻塞隊(duì)列什么是阻塞隊(duì)列什么是消費(fèi)生產(chǎn)者模型標(biāo)準(zhǔn)庫(kù)中的阻塞隊(duì)列…

文章目錄

  • 單例模式
    • 什么是單例模式
    • 餓漢模式
    • 懶漢模式
    • 多線程- 懶漢模式
      • 分析多線程問(wèn)題
      • 第一種添加sychronized的方式
      • 第二種添加sychronized的方式
      • 改進(jìn)第二種添加sychronized的方式(DCL檢查鎖)
  • 阻塞隊(duì)列
    • 什么是阻塞隊(duì)列
    • 什么是消費(fèi)生產(chǎn)者模型
    • 標(biāo)準(zhǔn)庫(kù)中的阻塞隊(duì)列
    • 消息隊(duì)列應(yīng)用的場(chǎng)景
    • 自己模擬實(shí)現(xiàn)阻塞隊(duì)列
  • 定時(shí)器
    • 標(biāo)準(zhǔn)庫(kù)中的定時(shí)器
    • 實(shí)現(xiàn)定時(shí)器
  • 工廠模式
  • 線程池
    • 線程池的一些問(wèn)題
    • 實(shí)現(xiàn)一個(gè)線程池
    • 創(chuàng)建系統(tǒng)自帶的線程池
  • wait和sleep的區(qū)別

單例模式

什么是單例模式

  • 單例模式能保證某個(gè)類在程序中只存在唯??份實(shí)例, ?不會(huì)創(chuàng)建出多個(gè)實(shí)例
  • 單例模式實(shí)現(xiàn)方式很多,最常用餓漢模式和懶漢模式實(shí)現(xiàn)

餓漢模式

  • 創(chuàng)建過(guò)程:
    – 1. 定義一個(gè)static修飾的變量,就可以包子這個(gè)變量全局唯一
    – 2.構(gòu)造方法私有化,防止變量被修改
    – 3.提供一個(gè)獲取變量的get靜態(tài)方法,通過(guò)類名的方式去調(diào)用
public class Singleton {//懶漢模式//創(chuàng)建一個(gè)私有靜態(tài)屬性,并且把對(duì)象new出來(lái)private static Singleton instance =new Singleton();//私有化構(gòu)造器private Singleton() {}//提供一個(gè)公共的靜態(tài)方法,返回單例對(duì)象public static Singleton getInstance() {return instance;}public static void main(String[] args) {Singleton s1 = Singleton.getInstance();Singleton s2 = Singleton.getInstance();System.out.println(s1 == s2); // true}
}
  • 把這種類加載時(shí)候就完成對(duì)象的初始化的創(chuàng)建方式,就叫”餓漢模式“
  • 這種模式存在的問(wèn)題是,可能對(duì)象創(chuàng)建了但是沒(méi)有使用,從而導(dǎo)致資源浪費(fèi)。

懶漢模式

public class SingLetonLazy {//創(chuàng)建一個(gè)對(duì)象不去new對(duì)象private static SingLetonLazy instance;//私有化構(gòu)造器private SingLetonLazy() {}//提供一個(gè)公共的靜態(tài)方法,返回單例對(duì)象public static SingLetonLazy getInstance() {if(instance==null) {instance=new SingLetonLazy();}return instance;}public static void main(String[] args) {SingLetonLazy s1 = SingLetonLazy.getInstance();SingLetonLazy s2 = SingLetonLazy.getInstance();System.out.println(s1 == s2); // true}
}
  • 懶漢模式創(chuàng)建對(duì)象,在要獲得單例對(duì)象的時(shí)候,創(chuàng)建,避免了資源的浪費(fèi)但是存在多線程安全問(wèn)題。

多線程- 懶漢模式

public class SingLetonLazy {private static SingLetonLazy instance;//私有化構(gòu)造器private SingLetonLazy() {}//提供一個(gè)公共的靜態(tài)方法,返回單例對(duì)象public static SingLetonLazy getInstance() {if(instance==null) {instance=new SingLetonLazy();}return instance;}public static void main(String[] args) {for (int i = 0; i < 10; i++) {Thread t1 =new Thread(()->{try {sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}SingLetonLazy s1 = SingLetonLazy.getInstance();System.out.println(s1);});t1.start();}}
}

在這里插入圖片描述
出現(xiàn)了多線程問(wèn)題。

分析多線程問(wèn)題

在這里插入圖片描述

第一種添加sychronized的方式

public static SingLetonLazy getInstance() {if(instance==null) {synchronized (SingLetonLazy.class){instance=new SingLetonLazy();}}return instance;}

在這里插入圖片描述

  • 這種寫法不能保證多線程安全

第二種添加sychronized的方式

public static SingLetonLazy getInstance() {synchronized (SingLetonLazy.class){if(instance==null) {instance=new SingLetonLazy();}}return instance;}

在這里插入圖片描述

  • 這種寫法似乎可以保證多線程安全,但是還是存在一個(gè)問(wèn)題,當(dāng)一個(gè)線程進(jìn)行這個(gè)方法,如果沒(méi)有初始化,則獲取鎖進(jìn)行初始化操作,此時(shí)單例對(duì)象被第一個(gè)線程創(chuàng)建完成,后面的線程以后永遠(yuǎn)不會(huì)在執(zhí)行new對(duì)象的操作,synchronized就沒(méi)必要添加了,第二次線程開(kāi)始這個(gè)加鎖解鎖都是無(wú)效的操作,lock和unlock對(duì)應(yīng)的鎖指令是互斥鎖,比較消耗系統(tǒng)資源。
  • 添加鎖本質(zhì)就會(huì)消耗很多資源

改進(jìn)第二種添加sychronized的方式(DCL檢查鎖)

 private volatile static SingLetonLazy instance;//給共享變量加上volatile

在這里插入圖片描述

public static SingLetonLazy getInstance() {//第一次判斷是否加鎖if(instance==null) {synchronized (SingLetonLazy.class) {判斷是否創(chuàng)建了一個(gè)對(duì)象if (instance == null) {instance = new SingLetonLazy();}}}return instance;}

在這里插入圖片描述
在這里插入圖片描述

阻塞隊(duì)列

什么是阻塞隊(duì)列

  1. 阻塞隊(duì)列本質(zhì)還是隊(duì)列,遵循”先進(jìn)先出“的原則
  2. 阻塞隊(duì)列是一種線程安全的數(shù)據(jù)結(jié)構(gòu),有以下特征
    – 當(dāng)隊(duì)列滿的時(shí)候,繼續(xù)入隊(duì)就會(huì)發(fā)生阻塞等待,直到隊(duì)列中有其他線程取出元素后,隊(duì)列有空位才會(huì)再次入隊(duì)
    – 當(dāng)隊(duì)列空的時(shí)候,繼續(xù)出隊(duì)就會(huì)放生阻塞等待,知道隊(duì)列中有其他線程插入元素時(shí)候,隊(duì)列有元素才會(huì)再次出隊(duì)
  3. 阻塞隊(duì)列適用于一種典型場(chǎng)景‘消費(fèi)生產(chǎn)者模型’

什么是消費(fèi)生產(chǎn)者模型

  1. 生產(chǎn)者消費(fèi)者模式就是通過(guò)一個(gè)容器解決消費(fèi)者和生產(chǎn)者的強(qiáng)耦合問(wèn)題。
  2. 生產(chǎn)者和消費(fèi)者不會(huì)直接影響,生產(chǎn)者生產(chǎn)的資源直接放入容器(阻塞隊(duì)列)中,消費(fèi)者消費(fèi)的資源,直接從容器(阻塞隊(duì)列)中拿。從而保證生產(chǎn)者不會(huì)生產(chǎn)資源等待消費(fèi)者消費(fèi),消費(fèi)者也不會(huì)等待生產(chǎn)者生產(chǎn)資源。
  3. 阻塞隊(duì)列相當(dāng)于一個(gè)緩沖區(qū),平衡生產(chǎn)者和消費(fèi)者的處理能力
    – 比如雙11時(shí)候,會(huì)涌入大量的支付訂單,這時(shí)候如果服務(wù)器直接處理這些訂單,可能就會(huì)把服務(wù)器擠爆,這時(shí)候中間設(shè)置一個(gè)阻塞隊(duì)列,把產(chǎn)生的大小支付訂單扔進(jìn)阻塞隊(duì)列里面,然后服務(wù)器根據(jù)自己的處理能力,從隊(duì)列里面取出要處理的訂單,從而達(dá)到削峰的效果,防止服務(wù)器被擠爆。
  4. 阻塞隊(duì)列也能使生產(chǎn)者和消費(fèi)者之間 解耦
    – 過(guò)年期間大家都會(huì)包餃子,搟餃子皮相當(dāng)于生產(chǎn)者,包餃子相當(dāng)于消費(fèi)者,中間放個(gè)案板,所有的餃子皮都放在案板上,包餃子皮的人直接從案板上取,搟餃子皮的可能是媽媽可能是爸爸可能是我,無(wú)論是誰(shuí)搟餃子皮消費(fèi)者都不關(guān)心,因?yàn)槎际菑陌赴迳先〉娘溩悠ぁ?/li>

標(biāo)準(zhǔn)庫(kù)中的阻塞隊(duì)列

  1. 在 Java 標(biāo)準(zhǔn)庫(kù)中內(nèi)置了阻塞隊(duì)列. 如果我們需要在一些程序中使用阻塞隊(duì)列, 直接使用標(biāo)準(zhǔn)庫(kù)中的即可.
    – BlockingQueue 是一個(gè)接口. 真正實(shí)現(xiàn)的類是 LinkedBlockingQueue.
    – put 方法用于阻塞式的入隊(duì)列, take 用于阻塞式的出隊(duì)列.
    – BlockingQueue 也有 offer, poll, peek 等方法, 但是這些方法不帶有阻塞特性.
  2. 創(chuàng)建一個(gè)BlockingQueue
    在這里插入圖片描述
    在這里插入圖片描述
    – 其中capacity是這個(gè)隊(duì)列的大小。

在這里插入圖片描述
– 這里設(shè)置一個(gè)三個(gè)大小的阻塞隊(duì)列,當(dāng)?shù)谒膫€(gè)元素入隊(duì)時(shí)候就會(huì)發(fā)生阻塞等待
在這里插入圖片描述
– 這里取出三個(gè)元素后,隊(duì)列為空,隊(duì)列阻塞等待
在這里插入圖片描述
在這里插入圖片描述
– put和take都會(huì)拋出一個(gè)InterrupteException異常

  1. 其他補(bǔ)充常問(wèn)的方法
    在這里插入圖片描述
    – add()
    在這里插入圖片描述
    – offer()
    在這里插入圖片描述
    – remove()
    在這里插入圖片描述
    – poll
    在這里插入圖片描述

消息隊(duì)列應(yīng)用的場(chǎng)景

  1. 解耦
    – 高內(nèi)聚,低耦合:業(yè)務(wù)強(qiáng)相關(guān)的代碼組織在一起,不相關(guān)的單獨(dú)定義便于以后的維護(hù),以為要把重復(fù)的代碼盡量抽象出來(lái),封裝成一個(gè)公共方法,在需要的地方直接調(diào)用這個(gè)方法即可
    – 生產(chǎn)消息的應(yīng)用程序把消息寫進(jìn)消息隊(duì)列(生產(chǎn)者),使用消息的應(yīng)用程序從消息隊(duì)列里面取出消息(消費(fèi)者)
    在這里插入圖片描述
    在這個(gè)模型中,服務(wù)器A要時(shí)刻感應(yīng)到服務(wù)器B,在調(diào)用的過(guò)程中雙方都要知道對(duì)方需要調(diào)用的參數(shù)和調(diào)用方式
    ,在ABC整個(gè)調(diào)用的鏈路中秒如果其中一個(gè)出現(xiàn)了問(wèn)題,就會(huì)影響整個(gè)業(yè)務(wù)執(zhí)行
    在這里插入圖片描述

  2. 削峰填谷(流量)
    – 針對(duì)流量暴增的時(shí)候使用消息隊(duì)列來(lái)進(jìn)行緩沖
    在這里插入圖片描述
    在這里插入圖片描述
    – 實(shí)例:
    在這里插入圖片描述

  3. 異步操作
    周末:我和我女朋友取買包子

  • 同步操作:她一直等我買包子回來(lái),開(kāi)始,中間這個(gè)過(guò)程啥也不干,同步發(fā)出請(qǐng)求后,必須要等待響應(yīng)才能- 進(jìn)行下一步操作
  • 異步操作:她讓我去之后,在家做點(diǎn)別的事情,比如,做點(diǎn)小菜,熬點(diǎn)稀飯,異步操作,發(fā)出請(qǐng)求之后,不需要等待響應(yīng),而做其他的事情,等待響應(yīng)主動(dòng)通知自己

自己模擬實(shí)現(xiàn)阻塞隊(duì)列

public class MyBlockingDeque {int [] arr;volatile int head=0;volatile int tail=0;volatile int size=0;MyBlockingDeque(int capacity){if(capacity<=0) {throw new RuntimeException("capacity must be positive");}arr = new int[capacity];}public void put(int val) throws InterruptedException {while(size>=arr.length) {synchronized (this){this.wait();}}arr[tail]=val;tail++;if(tail>=arr.length) {tail=0;}size++;synchronized (this){this.notifyAll();}}public synchronized int take() throws InterruptedException {while(size==0) {this.wait();}int val =arr[head];head++;if(head>=arr.length) {head=0;}size--;this.notifyAll();return val;}
}
class Main{public static void main(String[] args) throws InterruptedException {MyBlockingDeque myBlockingDeque = new MyBlockingDeque(10);int i=0;new Thread(()->{while (true){try {sleep(1000);int val = myBlockingDeque.take();System.out.println(Thread.currentThread().getName()+"取出成功"+val);} catch (InterruptedException e) {e.printStackTrace();}}}).start();while (true){myBlockingDeque.put(i);System.out.println(Thread.currentThread().getName()+"添加成功"+i);i++;}}
}

在這里插入圖片描述

  • put時(shí)候
    在這里插入圖片描述
  • take時(shí)候
    在這里插入圖片描述
  • 我們上鎖可以鎖代碼塊也可以方法
    在這里插入圖片描述
  • if改為while的原因是防止大量現(xiàn)場(chǎng)
    在這里插入圖片描述
    在這里插入圖片描述
    在這里插入圖片描述

定時(shí)器

標(biāo)準(zhǔn)庫(kù)中的定時(shí)器

  • 標(biāo)準(zhǔn)庫(kù)中定義一個(gè)TImer類。Timer類的核心方法為schedule
  • schedule包含兩個(gè)參數(shù),第一個(gè)參數(shù)指定要執(zhí)行的代碼任務(wù),第二個(gè)參數(shù)指定多場(chǎng)實(shí)際之后執(zhí)行。
import java.util.Timer;
import java.util.TimerTask;public class Demo_801 {public static void main(String[] args) {// 使用jdk中提供的類,創(chuàng)建一個(gè)定器Timer timer = new Timer();//向定時(shí)器添加任務(wù)timer.schedule(new TimerTask() {@Overridepublic void run() {System.out.println("Hello World!");}},1000);timer.schedule(new TimerTask() {@Overridepublic void run() {System.out.println("任務(wù)1");}},1500);timer.schedule(new TimerTask() {@Overridepublic void run() {System.out.println("任務(wù)2");}},2000);timer.schedule(new TimerTask() {@Overridepublic void run() {System.out.println("任務(wù)3");}},2500);}
}

ctrl+p查看方法的參數(shù)列表
在這里插入圖片描述
定義自己的任務(wù)
在這里插入圖片描述
延遲多久執(zhí)行的任務(wù)
在這里插入圖片描述
任務(wù)具體執(zhí)行的時(shí)間
在這里插入圖片描述

實(shí)現(xiàn)定時(shí)器

  1. 設(shè)計(jì)思路
  • 用一個(gè)類描述任務(wù)和執(zhí)行任務(wù)的時(shí)間
    – 具體任務(wù)邏輯用Runable表示,執(zhí)行時(shí)間可以用一個(gè)long型delay表示
  • 組織任務(wù)和時(shí)間對(duì)應(yīng)的對(duì)象
    – 可以考慮用一個(gè)阻塞隊(duì)列,我們選擇用PriorityBlockingQueue(),保證掃描任務(wù)時(shí)候,延時(shí)最少的任務(wù)先執(zhí)行

- 提供一個(gè)方法,
在這里插入圖片描述

  • 提供一個(gè)方法,提交任務(wù)
    在這里插入圖片描述

  • 要有一個(gè)線程執(zhí)行任務(wù)
    – 在哪里定義掃描線程?
    –在構(gòu)造方法里面直接定義線程
    – 1.取出隊(duì)首元素,2.判斷一下任務(wù)到執(zhí)行的時(shí)間沒(méi)有,3,如果到了就執(zhí)行,4.沒(méi)有就放回隊(duì)列
    在這里插入圖片描述

  1. 代碼實(shí)現(xiàn)
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.PriorityBlockingQueue;public class MyTimer {//用一個(gè)阻塞隊(duì)列來(lái)組織任務(wù)private BlockingQueue<MyTask> queue = new PriorityBlockingQueue<>();private Object lock = new Object();public MyTimer() {//創(chuàng)建線程Thread thread =new Thread(()->{while(true){try {//從隊(duì)列中取出任務(wù)MyTask task=this.queue.take();//判斷有沒(méi)有到執(zhí)行的時(shí)間long currentTime=System.currentTimeMillis();if(currentTime>=task.getTime()){//時(shí)間到了執(zhí)行task.getRunnable().run();} else{//時(shí)間沒(méi)到,將任務(wù)放回隊(duì)列中this.queue.put(task);}} catch (InterruptedException e) {throw new RuntimeException(e);}}});thread.start();}/*** 添加定時(shí)任務(wù)* @param runnable 任務(wù)* @param delay 延時(shí)* @throws InterruptedException*/public void schedule(Runnable runnable,long delay) throws InterruptedException {//根據(jù)傳的參數(shù)構(gòu)造一個(gè)MyTask對(duì)象MyTask task=new MyTask(runnable,delay);//將這個(gè)MyTask對(duì)象阻塞放入隊(duì)列中queue.put(task);}
}//MyTask類,用于封裝任務(wù)和執(zhí)行時(shí)間
class MyTask implements Comparable<MyTask>{//任務(wù)private Runnable runnable;//執(zhí)行時(shí)間private long time;public MyTask(Runnable runnable, long delay) {//增強(qiáng)代碼健壯性if(runnable==null){throw new IllegalArgumentException("任務(wù)不能為空");}if(delay<0) {throw new IllegalArgumentException("延遲時(shí)間不能為負(fù)數(shù)");}this.runnable = runnable;//計(jì)算出任務(wù)的執(zhí)行時(shí)間this.time = delay+System.currentTimeMillis();}public Runnable getRunnable() {return runnable;}public long getTime() {return time;}@Overridepublic int compareTo(MyTask o) {if(this.getTime()<o.getTime()){return -1;} else if(this.getTime()==o.getTime()){return 0;}else {return 1;}//萬(wàn)一時(shí)間超過(guò)了long的范圍溢出,怎么辦?用上面的比較比較好//return (int)(this.getTime()-o.getTime());}
}
public class Test {public static void main(String[] args) throws InterruptedException {MyTimer timer = new MyTimer();timer.schedule(new Runnable(){@Overridepublic void run() {System.out.println("任務(wù)1");}},1000);timer.schedule(new Runnable(){@Overridepublic void run() {System.out.println("任務(wù)2");}},500);timer.schedule(new Runnable(){@Overridepublic void run() {System.out.println("任務(wù)3");}},2000);//timer.schedule(null,-100);//任務(wù)加強(qiáng)健壯性}
}
  • 注意事項(xiàng):
    – 注意我們要實(shí)現(xiàn)Conparable接口指定排序規(guī)則
    在這里插入圖片描述
    在這里插入圖片描述

– 我們要添加校驗(yàn),防止非法的輸入
在這里插入圖片描述

– 解決數(shù)據(jù)可能會(huì)溢出的問(wèn)題,比如設(shè)置的時(shí)間
在這里插入圖片描述

  1. 再次深度優(yōu)化我們代碼
    在這里插入圖片描述
  • 以上代碼我們存在“忙等”的情況
  • 優(yōu)化后的代碼
    在這里插入圖片描述
    – 這里注意一下這個(gè)lambda表達(dá)式中的this引用的是他所在對(duì)象的實(shí)例。
  • 新的問(wèn)題:當(dāng)任務(wù)1在等待時(shí)候,這時(shí)候如果又put進(jìn)來(lái)一個(gè)新的任務(wù),這個(gè)等待的時(shí)間就有問(wèn)題。再次優(yōu)化
    在這里插入圖片描述
    每添加新的任務(wù)都進(jìn)行一次喚醒,保證執(zhí)行的永遠(yuǎn)是最少延時(shí)的任務(wù)。
  • 從CPU調(diào)度的過(guò)程中可以會(huì)產(chǎn)生的執(zhí)行順序的問(wèn)題,或當(dāng)一個(gè)線程執(zhí)行到一半的時(shí)間被掉調(diào)度走的現(xiàn)象。
    在這里插入圖片描述
    這個(gè)線程造成的原因就是沒(méi)有保證原子性。
  • 優(yōu)化代碼
    在這里插入圖片描述

在這里插入圖片描述

  • 再次觀察一種極端情況
    在這里插入圖片描述
    – 我們發(fā)現(xiàn)當(dāng)我們把三個(gè)任務(wù)的延時(shí)時(shí)間設(shè)置為0的時(shí)候,結(jié)果只執(zhí)行了任務(wù)1,我們進(jìn)行調(diào)試
    在這里插入圖片描述
    – 調(diào)試之后我們又發(fā)現(xiàn)是正常情況,但是運(yùn)行時(shí)候不符合我們的預(yù)期結(jié)果,這時(shí)候我們不要慌,我們用jconsole工具去查看下掃描情況
    在這里插入圖片描述
  • 我們發(fā)現(xiàn)在MyTimer。java22行出現(xiàn)了問(wèn)題
  • 在這里插入圖片描述

1.創(chuàng)建一個(gè)定時(shí)器
2.向定時(shí)器添加任務(wù)1
3.第一個(gè)任務(wù)被添加到阻塞隊(duì)列中
4.掃描線程啟動(dòng),處理第一個(gè)任務(wù)
5.掃描線程1循環(huán),獲得第二個(gè)任務(wù)時(shí)候,隊(duì)列為空,開(kāi)始等待,同時(shí)掃描線程獲得鎖
6.主線程向阻塞隊(duì)列添加任務(wù)時(shí)候,等待掃描對(duì)象的對(duì)象,由于掃描線程無(wú)法釋放鎖對(duì)象,主線程也就獲取不到鎖對(duì)象,造成相互等待,造成死鎖

  • 我們?cè)俅蝺?yōu)化代碼創(chuàng)造一個(gè)后臺(tái)掃描線程,只做定時(shí)喚醒操作,定時(shí)1秒或者10ms,喚醒一次

在這里插入圖片描述
-最終的代碼

public class MyTimer {//用一個(gè)阻塞隊(duì)列來(lái)組織任務(wù)private BlockingQueue<MyTask> queue = new PriorityBlockingQueue<>();private Object lock = new Object();public MyTimer() {//創(chuàng)建線程Thread thread =new Thread(()->{while(true) {try {synchronized (this) {//從隊(duì)列中取出任務(wù)MyTask task = this.queue.take();//判斷有沒(méi)有到執(zhí)行的時(shí)間long currentTime = System.currentTimeMillis();if (currentTime >= task.getTime()) {//時(shí)間到了執(zhí)行task.getRunnable().run();} else {//時(shí)間沒(méi)到,將任務(wù)放回隊(duì)列中long waitTime = task.getTime() - currentTime;this.queue.put(task);this.wait(waitTime);}}} catch (InterruptedException e) {throw new RuntimeException(e);}}});thread.start();//創(chuàng)建守護(hù)線程,定時(shí)喚醒一次Thread deamonThread=new Thread(()->{synchronized (this) {//喚醒一次this.notifyAll();//每隔100ms喚醒一次try {TimeUnit.MILLISECONDS.sleep(100);} catch (InterruptedException e) {throw new RuntimeException(e);}}});//設(shè)置為守護(hù)線程deamonThread.setDaemon(true);deamonThread.start();}/*** 添加定時(shí)任務(wù)* @param runnable 任務(wù)* @param delay 延時(shí)* @throws InterruptedException*/public void schedule(Runnable runnable,long delay) throws InterruptedException {//根據(jù)傳的參數(shù)構(gòu)造一個(gè)MyTask對(duì)象MyTask task=new MyTask(runnable,delay);//將這個(gè)MyTask對(duì)象阻塞放入隊(duì)列中queue.put(task);System.out.println("任務(wù)添加成功");}
}//MyTask類,用于封裝任務(wù)和執(zhí)行時(shí)間
class MyTask implements Comparable<MyTask>{//任務(wù)private Runnable runnable;//執(zhí)行時(shí)間private long time;public MyTask(Runnable runnable, long delay) {//增強(qiáng)代碼健壯性if(runnable==null){throw new IllegalArgumentException("任務(wù)不能為空");}if(delay<0) {throw new IllegalArgumentException("延遲時(shí)間不能為負(fù)數(shù)");}this.runnable = runnable;//計(jì)算出任務(wù)的執(zhí)行時(shí)間this.time = delay+System.currentTimeMillis();}public Runnable getRunnable() {return runnable;}public long getTime() {return time;}@Overridepublic int compareTo(MyTask o) {if(this.getTime()<o.getTime()){return -1;} else if(this.getTime()==o.getTime()){return 0;}else {return 1;}//萬(wàn)一時(shí)間超過(guò)了long的范圍溢出,怎么辦?用上面的比較比較好//return (int)(this.getTime()-o.getTime());}
public class Test {public static void main(String[] args) throws InterruptedException {MyTimer timer = new MyTimer();timer.schedule(new Runnable(){@Overridepublic void run() {System.out.println("任務(wù)1");}},0);timer.schedule(new Runnable(){@Overridepublic void run() {System.out.println("任務(wù)2");}},0);timer.schedule(new Runnable(){@Overridepublic void run() {System.out.println("任務(wù)3");}},0);//timer.schedule(null,-100);//任務(wù)加強(qiáng)健壯性}
}

工廠模式

  • 先看出現(xiàn)的問(wèn)題在這里插入圖片描述
    我們這里造成了重載參數(shù)的相同,但是我們就是要這樣的構(gòu)造方法我們?cè)趺唇鉀Q呢?

在這里插入圖片描述
工廠方法模式。根據(jù)不同的業(yè)務(wù)需求定義不同的方法來(lái)獲取對(duì)象。

線程池

線程池的一些問(wèn)題

  • 什么是線程池
    1.線程池就是一次創(chuàng)建多個(gè)線程,把這些線程放進(jìn)一個(gè)池中,用的時(shí)候從池中取出,用完就還回去
  • 為什么要用線程池
    我們首先要明白,線程的創(chuàng)建和銷毀都會(huì)消耗大量的資源,線程池中的線程當(dāng)有任務(wù)的時(shí)候,就會(huì)執(zhí)行任務(wù),沒(méi)有任務(wù)的時(shí)候就阻塞等待,并不銷毀線程,線程池最?的好處就是減少每次啟動(dòng)、銷毀線程的損耗。
  • 為什么使用線程池可以提升效率
    少量創(chuàng)建,少量銷毀,創(chuàng)建一個(gè)線程要分為內(nèi)核態(tài)和用戶態(tài),用戶態(tài)相當(dāng)于jvm層面,內(nèi)核太相當(dāng)于操作系統(tǒng)層面,當(dāng)我們?cè)趈vm層面創(chuàng)建一個(gè)線程,就要在操作系統(tǒng)層面創(chuàng)建對(duì)應(yīng)指令,就會(huì)消耗大量資源,消耗線程也如此,所以線程池減少了頻繁的銷毀和創(chuàng)建,用的時(shí)候就直接在線程池里面用已經(jīng)創(chuàng)建多的,從而提升效率。
  • 怎么用?
    – jdk給我們提供了一組針對(duì)不同場(chǎng)景的線程池實(shí)例
public static void main(String[] args) {//1.用來(lái)處理大量短時(shí)間的任務(wù)的線程池,如果池沒(méi)有可用的線程將創(chuàng)建線程,如果線程空閑60秒將收回并移除緩存ExecutorService cachedThreadpool= Executors.newCachedThreadPool();//2.創(chuàng)建一個(gè)操作無(wú)界隊(duì)列,線程池大小固定的線程池ExecutorService fixedThreadpool= Executors.newFixedThreadPool(5);//可以指定線程數(shù)量//3.創(chuàng)建一個(gè)操作無(wú)界隊(duì)列,只有一個(gè)線程的線程池ExecutorService singleThreadExecutor= Executors.newSingleThreadExecutor();//4.創(chuàng)建一個(gè)單線程執(zhí)行器,可以加時(shí)間給定時(shí)間后執(zhí)行或者定期執(zhí)行ScheduledExecutorService singleThreadScheduledExecutor= Executors.newSingleThreadScheduledExecutor();//5.創(chuàng)建一個(gè)指定大小的線程池,可以加時(shí)間給定時(shí)間后執(zhí)行或者定期執(zhí)行ScheduledExecutorService scheduledThreadpool= Executors.newScheduledThreadPool(5);//6.創(chuàng)建一個(gè)指定大小(不傳參,為當(dāng)前機(jī)器的cpu核數(shù))的線程池,并行處理任務(wù),不保證處理順序Executors.newWorkStealingPool();
}
Runtime.getRuntime().availableProcessors()
獲取系統(tǒng)的cpu核數(shù)

實(shí)現(xiàn)一個(gè)線程池

  • 先構(gòu)思思路(先描述,再組織)
  1. 用Runable描述任務(wù)
  2. 組織管理任務(wù)可以使用一個(gè)隊(duì)列,可以使用阻塞隊(duì)列取實(shí)現(xiàn)
  3. 提供一個(gè)向隊(duì)列的添加任務(wù)的方法
  4. 創(chuàng)建多個(gè)線程,掃描隊(duì)列里面的任務(wù),有任務(wù)時(shí)候執(zhí)行,沒(méi)有任務(wù)時(shí)候等待
public class MyExectorService {//定義阻塞隊(duì)列阻止任務(wù)private BlockingQueue<Runnable> queue=new LinkedBlockingQueue(100);private  static Object lock=new Object();public MyExectorService(int threadNum){for (int i = 0; i < threadNum; i++){Thread thread=new Thread(()->{//不停掃描隊(duì)列while (true) {try {synchronized (lock){Runnable runable=  queue.take();runable.run();}TimeUnit.MILLISECONDS.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}//take()方法會(huì)阻塞,直到隊(duì)列中有任務(wù)});//啟動(dòng)線程thread.start();}}/*** 提交任務(wù)到線程池中* @param runnable 具體的任務(wù)* @throws InterruptedException*/public void sumbit(Runnable runnable) throws InterruptedException {if(runnable==null){throw new IllegalArgumentException("任務(wù)不能為空");}//把任務(wù)加入隊(duì)列中queue.put(runnable);}}
class Test1{public static void main(String[] args) throws InterruptedException {MyExectorService myExectorService=new MyExectorService(3);AtomicInteger j= new AtomicInteger();for (int i = 0; i < 10; i++) {myExectorService.sumbit(() -> {System.out.println(Thread.currentThread().getName() + " " + j);j.getAndIncrement();});if(i%3==0){TimeUnit.SECONDS.sleep(1);}}}
}

創(chuàng)建系統(tǒng)自帶的線程池

  • 前面jdk提供的線程池比較固定,也就是說(shuō)我們不能自己定制,但是我們看底層代碼時(shí)發(fā)現(xiàn),這些線程池都是對(duì)ThreadPoolExecutor的封裝
    在這里插入圖片描述
  • 那我們可以根據(jù)ThreadPoolEecutor創(chuàng)建一個(gè)自定義線程池

在這里插入圖片描述
用現(xiàn)實(shí)的兩個(gè)例子去模擬線程工作的原理
周末去吃飯
在這里插入圖片描述
銀行辦理業(yè)務(wù)
在這里插入圖片描述

  • 線程池的拒絕策略詳解
    在這里插入圖片描述
    在這里插入圖片描述
  • 我們注意一下,3和4是不會(huì)拋出異常的,1和2是會(huì)拋出異常的,放棄的任務(wù)永遠(yuǎn)都找不回來(lái),所以指定拒絕策略的時(shí)候,要關(guān)注任務(wù)是不是必須要執(zhí)行,如果必須要執(zhí)行,就指定“返回調(diào)用者”,否則選1,3,4一個(gè)即可
public static void main(String[] args) {ThreadPoolExecutor threadPool=new ThreadPoolExecutor(2,5,10, TimeUnit.SECONDS,new LinkedBlockingQueue<>(7),new ThreadPoolExecutor.AbortPolicy());for (int i = 0; i < 100; i++) {int takeI=i;threadPool.submit(new Runnable() {@Overridepublic void run() {System.out.println(Thread.currentThread().getName()+" 執(zhí)行任務(wù) "+takeI);}});}}
  • 直接拒絕
    實(shí)際只執(zhí)行幾個(gè)后面的都沒(méi)執(zhí)行
    在這里插入圖片描述
    在這里插入圖片描述
  • 返回給調(diào)用者
    有一部分代碼返回給調(diào)用者main執(zhí)行了
  public static void main(String[] args) {ThreadPoolExecutor threadPool=new ThreadPoolExecutor(2,5,10, TimeUnit.SECONDS,new LinkedBlockingQueue<>(7),new ThreadPoolExecutor.CallerRunsPolicy());for (int i = 0; i < 100; i++) {int takeI=i;threadPool.submit(new Runnable() {@Overridepublic void run() {System.out.println(Thread.currentThread().getName()+" 執(zhí)行任務(wù) "+takeI);}});}}

在這里插入圖片描述

  • 放棄最早的任務(wù)
public static void main(String[] args) {ThreadPoolExecutor threadPool=new ThreadPoolExecutor(2,5,10, TimeUnit.SECONDS,new LinkedBlockingQueue<>(7),new ThreadPoolExecutor.DiscardOldestPolicy());for (int i = 0; i < 100; i++) {int takeI=i;threadPool.submit(new Runnable() {@Overridepublic void run() {System.out.println(Thread.currentThread().getName()+" 執(zhí)行任務(wù) "+takeI);}});}}

在這里插入圖片描述

  • 放棄最新的任務(wù)
public static void main(String[] args) {ThreadPoolExecutor threadPool=new ThreadPoolExecutor(2,5,10, TimeUnit.SECONDS,new LinkedBlockingQueue<>(7),new ThreadPoolExecutor.DiscardPolicy());for (int i = 0; i < 100; i++) {int takeI=i;threadPool.submit(new Runnable() {@Overridepublic void run() {System.out.println(Thread.currentThread().getName()+" 執(zhí)行任務(wù) "+takeI);}});}}

在這里插入圖片描述

wait和sleep的區(qū)別

1.共同點(diǎn),讓線程休眠一會(huì)
2.從實(shí)現(xiàn)使用上來(lái)說(shuō)是兩種不同的方法
wait是Object類的方法,與鎖相關(guān),配合sychronized一起使用,調(diào)用wait之后會(huì)釋放鎖
sleep是Thread類的方法,與鎖無(wú)關(guān)
wait可以通過(guò)notify和指定直線的方法喚醒,喚醒之后重新競(jìng)爭(zhēng)鎖資源
sleep只能通過(guò)超時(shí)時(shí)間喚醒

  • 補(bǔ)充
    在這里插入圖片描述
http://m.aloenet.com.cn/news/34669.html

相關(guān)文章:

  • 相冊(cè)模版網(wǎng)站圖片展示成人再就業(yè)培訓(xùn)班
  • 網(wǎng)站流量少宣傳產(chǎn)品的方式
  • 請(qǐng)人做網(wǎng)站后臺(tái)密碼推廣模式包括哪些模式
  • 復(fù)興網(wǎng)站制作網(wǎng)絡(luò)推廣文案策劃
  • 成都網(wǎng)站建設(shè)哪兒濟(jì)南興田德潤(rùn)怎么聯(lián)系婁底seo
  • 網(wǎng)站的反鏈要怎么做近期國(guó)內(nèi)熱點(diǎn)新聞事件
  • 網(wǎng)站建設(shè)好學(xué)嗎google ads 推廣
  • 九江網(wǎng)站建設(shè)多少錢百度推廣客服電話24小時(shí)
  • 2012搭建wordpress網(wǎng)站seo專員招聘
  • 技術(shù)支持 東莞網(wǎng)站建設(shè)舞蹈培訓(xùn)免費(fèi)的網(wǎng)頁(yè)制作軟件
  • 怎么做網(wǎng)站排名優(yōu)化電子商務(wù)平臺(tái)
  • 珠海網(wǎng)站建立seo外鏈在線提交工具
  • 鮮花商城網(wǎng)站建設(shè)怎么找拉新推廣平臺(tái)
  • 手機(jī)app制作網(wǎng)站模板seo兼職論壇
  • 專業(yè)網(wǎng)站優(yōu)化報(bào)價(jià)優(yōu)化推薦
  • wordpress復(fù)制他人的網(wǎng)站網(wǎng)站收錄情況查詢
  • 推廣優(yōu)化濟(jì)南網(wǎng)絡(luò)優(yōu)化網(wǎng)站
  • 網(wǎng)站改版的原因微信怎么推廣自己的產(chǎn)品
  • wordpress 獲取文章評(píng)論百度app關(guān)鍵詞優(yōu)化
  • 博客做單頁(yè)網(wǎng)站網(wǎng)站建設(shè)的方法有哪些
  • 自己做的網(wǎng)頁(yè)怎么連接到網(wǎng)站某個(gè)產(chǎn)品營(yíng)銷推廣方案
  • 紅色 網(wǎng)站配色seo優(yōu)化方式
  • 怎樣做網(wǎng)站導(dǎo)購(gòu)教程足球排名最新排名世界
  • 打開(kāi)網(wǎng)站后直接做跳轉(zhuǎn)頁(yè)面嗎百度怎么打廣告
  • 給企業(yè)做網(wǎng)站如何定價(jià)百度快照收錄
  • 沈陽(yáng)高端做網(wǎng)站建設(shè)時(shí)事熱點(diǎn)新聞
  • 旅游網(wǎng)站開(kāi)發(fā)論文企業(yè)優(yōu)化推廣
  • wordpress 755權(quán)限深圳seo優(yōu)化外包公司
  • html格式網(wǎng)站北京網(wǎng)站優(yōu)化校學(xué)費(fèi)
  • php網(wǎng)站開(kāi)發(fā)工程師待遇百度快照是啥