手機網站模板開發(fā)工具seo網絡營銷推廣公司深圳
文章目錄
- 單例模式
- 什么是單例模式
- 餓漢模式
- 懶漢模式
- 多線程- 懶漢模式
- 分析多線程問題
- 第一種添加sychronized的方式
- 第二種添加sychronized的方式
- 改進第二種添加sychronized的方式(DCL檢查鎖)
- 阻塞隊列
- 什么是阻塞隊列
- 什么是消費生產者模型
- 標準庫中的阻塞隊列
- 消息隊列應用的場景
- 自己模擬實現(xiàn)阻塞隊列
- 定時器
- 標準庫中的定時器
- 實現(xiàn)定時器
- 工廠模式
- 線程池
- 線程池的一些問題
- 實現(xiàn)一個線程池
- 創(chuàng)建系統(tǒng)自帶的線程池
- wait和sleep的區(qū)別
單例模式
什么是單例模式
- 單例模式能保證某個類在程序中只存在唯??份實例, ?不會創(chuàng)建出多個實例
- 單例模式實現(xiàn)方式很多,最常用餓漢模式和懶漢模式實現(xiàn)
餓漢模式
- 創(chuàng)建過程:
– 1. 定義一個static修飾的變量,就可以包子這個變量全局唯一
– 2.構造方法私有化,防止變量被修改
– 3.提供一個獲取變量的get靜態(tài)方法,通過類名的方式去調用
public class Singleton {//懶漢模式//創(chuàng)建一個私有靜態(tài)屬性,并且把對象new出來private static Singleton instance =new Singleton();//私有化構造器private Singleton() {}//提供一個公共的靜態(tài)方法,返回單例對象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}
}
- 把這種類加載時候就完成對象的初始化的創(chuàng)建方式,就叫”餓漢模式“
- 這種模式存在的問題是,可能對象創(chuàng)建了但是沒有使用,從而導致資源浪費。
懶漢模式
public class SingLetonLazy {//創(chuàng)建一個對象不去new對象private static SingLetonLazy instance;//私有化構造器private SingLetonLazy() {}//提供一個公共的靜態(tài)方法,返回單例對象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)建對象,在要獲得單例對象的時候,創(chuàng)建,避免了資源的浪費但是存在多線程安全問題。
多線程- 懶漢模式
public class SingLetonLazy {private static SingLetonLazy instance;//私有化構造器private SingLetonLazy() {}//提供一個公共的靜態(tài)方法,返回單例對象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)了多線程問題。
分析多線程問題
第一種添加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;}
- 這種寫法似乎可以保證多線程安全,但是還是存在一個問題,當一個線程進行這個方法,如果沒有初始化,則獲取鎖進行初始化操作,此時單例對象被第一個線程創(chuàng)建完成,后面的線程以后永遠不會在執(zhí)行new對象的操作,synchronized就沒必要添加了,第二次線程開始這個加鎖解鎖都是無效的操作,lock和unlock對應的鎖指令是互斥鎖,比較消耗系統(tǒng)資源。
- 添加鎖本質就會消耗很多資源
改進第二種添加sychronized的方式(DCL檢查鎖)
private volatile static SingLetonLazy instance;//給共享變量加上volatile
public static SingLetonLazy getInstance() {//第一次判斷是否加鎖if(instance==null) {synchronized (SingLetonLazy.class) {判斷是否創(chuàng)建了一個對象if (instance == null) {instance = new SingLetonLazy();}}}return instance;}
阻塞隊列
什么是阻塞隊列
- 阻塞隊列本質還是隊列,遵循”先進先出“的原則
- 阻塞隊列是一種線程安全的數(shù)據(jù)結構,有以下特征
– 當隊列滿的時候,繼續(xù)入隊就會發(fā)生阻塞等待,直到隊列中有其他線程取出元素后,隊列有空位才會再次入隊
– 當隊列空的時候,繼續(xù)出隊就會放生阻塞等待,知道隊列中有其他線程插入元素時候,隊列有元素才會再次出隊 - 阻塞隊列適用于一種典型場景‘消費生產者模型’
什么是消費生產者模型
- 生產者消費者模式就是通過一個容器解決消費者和生產者的強耦合問題。
- 生產者和消費者不會直接影響,生產者生產的資源直接放入容器(阻塞隊列)中,消費者消費的資源,直接從容器(阻塞隊列)中拿。從而保證生產者不會生產資源等待消費者消費,消費者也不會等待生產者生產資源。
- 阻塞隊列相當于一個緩沖區(qū),平衡生產者和消費者的處理能力
– 比如雙11時候,會涌入大量的支付訂單,這時候如果服務器直接處理這些訂單,可能就會把服務器擠爆,這時候中間設置一個阻塞隊列,把產生的大小支付訂單扔進阻塞隊列里面,然后服務器根據(jù)自己的處理能力,從隊列里面取出要處理的訂單,從而達到削峰的效果,防止服務器被擠爆。 - 阻塞隊列也能使生產者和消費者之間 解耦
– 過年期間大家都會包餃子,搟餃子皮相當于生產者,包餃子相當于消費者,中間放個案板,所有的餃子皮都放在案板上,包餃子皮的人直接從案板上取,搟餃子皮的可能是媽媽可能是爸爸可能是我,無論是誰搟餃子皮消費者都不關心,因為都是從案板上取的餃子皮。
標準庫中的阻塞隊列
- 在 Java 標準庫中內置了阻塞隊列. 如果我們需要在一些程序中使用阻塞隊列, 直接使用標準庫中的即可.
– BlockingQueue 是一個接口. 真正實現(xiàn)的類是 LinkedBlockingQueue.
– put 方法用于阻塞式的入隊列, take 用于阻塞式的出隊列.
– BlockingQueue 也有 offer, poll, peek 等方法, 但是這些方法不帶有阻塞特性. - 創(chuàng)建一個BlockingQueue
– 其中capacity是這個隊列的大小。
– 這里設置一個三個大小的阻塞隊列,當?shù)谒膫€元素入隊時候就會發(fā)生阻塞等待
– 這里取出三個元素后,隊列為空,隊列阻塞等待
– put和take都會拋出一個InterrupteException異常
- 其他補充常問的方法
– add()
– offer()
– remove()
– poll
消息隊列應用的場景
-
解耦
– 高內聚,低耦合:業(yè)務強相關的代碼組織在一起,不相關的單獨定義便于以后的維護,以為要把重復的代碼盡量抽象出來,封裝成一個公共方法,在需要的地方直接調用這個方法即可
– 生產消息的應用程序把消息寫進消息隊列(生產者),使用消息的應用程序從消息隊列里面取出消息(消費者)
在這個模型中,服務器A要時刻感應到服務器B,在調用的過程中雙方都要知道對方需要調用的參數(shù)和調用方式
,在ABC整個調用的鏈路中秒如果其中一個出現(xiàn)了問題,就會影響整個業(yè)務執(zhí)行
-
削峰填谷(流量)
– 針對流量暴增的時候使用消息隊列來進行緩沖
– 實例:
-
異步操作
周末:我和我女朋友取買包子
- 同步操作:她一直等我買包子回來,開始,中間這個過程啥也不干,同步發(fā)出請求后,必須要等待響應才能- 進行下一步操作
- 異步操作:她讓我去之后,在家做點別的事情,比如,做點小菜,熬點稀飯,異步操作,發(fā)出請求之后,不需要等待響應,而做其他的事情,等待響應主動通知自己
自己模擬實現(xiàn)阻塞隊列
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時候
- take時候
- 我們上鎖可以鎖代碼塊也可以方法
- if改為while的原因是防止大量現(xiàn)場
定時器
標準庫中的定時器
- 標準庫中定義一個TImer類。Timer類的核心方法為schedule
- schedule包含兩個參數(shù),第一個參數(shù)指定要執(zhí)行的代碼任務,第二個參數(shù)指定多場實際之后執(zhí)行。
import java.util.Timer;
import java.util.TimerTask;public class Demo_801 {public static void main(String[] args) {// 使用jdk中提供的類,創(chuàng)建一個定器Timer timer = new Timer();//向定時器添加任務timer.schedule(new TimerTask() {@Overridepublic void run() {System.out.println("Hello World!");}},1000);timer.schedule(new TimerTask() {@Overridepublic void run() {System.out.println("任務1");}},1500);timer.schedule(new TimerTask() {@Overridepublic void run() {System.out.println("任務2");}},2000);timer.schedule(new TimerTask() {@Overridepublic void run() {System.out.println("任務3");}},2500);}
}
ctrl+p查看方法的參數(shù)列表
定義自己的任務
延遲多久執(zhí)行的任務
任務具體執(zhí)行的時間
實現(xiàn)定時器
- 設計思路
- 用一個類描述任務和執(zhí)行任務的時間
– 具體任務邏輯用Runable表示,執(zhí)行時間可以用一個long型delay表示 - 組織任務和時間對應的對象
– 可以考慮用一個阻塞隊列,我們選擇用PriorityBlockingQueue(),保證掃描任務時候,延時最少的任務先執(zhí)行
-
提供一個方法,提交任務
-
要有一個線程執(zhí)行任務
– 在哪里定義掃描線程?
–在構造方法里面直接定義線程
– 1.取出隊首元素,2.判斷一下任務到執(zhí)行的時間沒有,3,如果到了就執(zhí)行,4.沒有就放回隊列
- 代碼實現(xiàn)
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.PriorityBlockingQueue;public class MyTimer {//用一個阻塞隊列來組織任務private BlockingQueue<MyTask> queue = new PriorityBlockingQueue<>();private Object lock = new Object();public MyTimer() {//創(chuàng)建線程Thread thread =new Thread(()->{while(true){try {//從隊列中取出任務MyTask task=this.queue.take();//判斷有沒有到執(zhí)行的時間long currentTime=System.currentTimeMillis();if(currentTime>=task.getTime()){//時間到了執(zhí)行task.getRunnable().run();} else{//時間沒到,將任務放回隊列中this.queue.put(task);}} catch (InterruptedException e) {throw new RuntimeException(e);}}});thread.start();}/*** 添加定時任務* @param runnable 任務* @param delay 延時* @throws InterruptedException*/public void schedule(Runnable runnable,long delay) throws InterruptedException {//根據(jù)傳的參數(shù)構造一個MyTask對象MyTask task=new MyTask(runnable,delay);//將這個MyTask對象阻塞放入隊列中queue.put(task);}
}//MyTask類,用于封裝任務和執(zhí)行時間
class MyTask implements Comparable<MyTask>{//任務private Runnable runnable;//執(zhí)行時間private long time;public MyTask(Runnable runnable, long delay) {//增強代碼健壯性if(runnable==null){throw new IllegalArgumentException("任務不能為空");}if(delay<0) {throw new IllegalArgumentException("延遲時間不能為負數(shù)");}this.runnable = runnable;//計算出任務的執(zhí)行時間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;}//萬一時間超過了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("任務1");}},1000);timer.schedule(new Runnable(){@Overridepublic void run() {System.out.println("任務2");}},500);timer.schedule(new Runnable(){@Overridepublic void run() {System.out.println("任務3");}},2000);//timer.schedule(null,-100);//任務加強健壯性}
}
- 注意事項:
– 注意我們要實現(xiàn)Conparable接口指定排序規(guī)則
– 我們要添加校驗,防止非法的輸入
– 解決數(shù)據(jù)可能會溢出的問題,比如設置的時間
- 再次深度優(yōu)化我們代碼
- 以上代碼我們存在“忙等”的情況
- 優(yōu)化后的代碼
– 這里注意一下這個lambda表達式中的this引用的是他所在對象的實例。 - 新的問題:當任務1在等待時候,這時候如果又put進來一個新的任務,這個等待的時間就有問題。再次優(yōu)化
每添加新的任務都進行一次喚醒,保證執(zhí)行的永遠是最少延時的任務。 - 從CPU調度的過程中可以會產生的執(zhí)行順序的問題,或當一個線程執(zhí)行到一半的時間被掉調度走的現(xiàn)象。
這個線程造成的原因就是沒有保證原子性。 - 優(yōu)化代碼
- 再次觀察一種極端情況
– 我們發(fā)現(xiàn)當我們把三個任務的延時時間設置為0的時候,結果只執(zhí)行了任務1,我們進行調試
– 調試之后我們又發(fā)現(xiàn)是正常情況,但是運行時候不符合我們的預期結果,這時候我們不要慌,我們用jconsole工具去查看下掃描情況
- 我們發(fā)現(xiàn)在MyTimer。java22行出現(xiàn)了問題
1.創(chuàng)建一個定時器
2.向定時器添加任務1
3.第一個任務被添加到阻塞隊列中
4.掃描線程啟動,處理第一個任務
5.掃描線程1循環(huán),獲得第二個任務時候,隊列為空,開始等待,同時掃描線程獲得鎖
6.主線程向阻塞隊列添加任務時候,等待掃描對象的對象,由于掃描線程無法釋放鎖對象,主線程也就獲取不到鎖對象,造成相互等待,造成死鎖
- 我們再次優(yōu)化代碼創(chuàng)造一個后臺掃描線程,只做定時喚醒操作,定時1秒或者10ms,喚醒一次
-最終的代碼
public class MyTimer {//用一個阻塞隊列來組織任務private BlockingQueue<MyTask> queue = new PriorityBlockingQueue<>();private Object lock = new Object();public MyTimer() {//創(chuàng)建線程Thread thread =new Thread(()->{while(true) {try {synchronized (this) {//從隊列中取出任務MyTask task = this.queue.take();//判斷有沒有到執(zhí)行的時間long currentTime = System.currentTimeMillis();if (currentTime >= task.getTime()) {//時間到了執(zhí)行task.getRunnable().run();} else {//時間沒到,將任務放回隊列中long waitTime = task.getTime() - currentTime;this.queue.put(task);this.wait(waitTime);}}} catch (InterruptedException e) {throw new RuntimeException(e);}}});thread.start();//創(chuàng)建守護線程,定時喚醒一次Thread deamonThread=new Thread(()->{synchronized (this) {//喚醒一次this.notifyAll();//每隔100ms喚醒一次try {TimeUnit.MILLISECONDS.sleep(100);} catch (InterruptedException e) {throw new RuntimeException(e);}}});//設置為守護線程deamonThread.setDaemon(true);deamonThread.start();}/*** 添加定時任務* @param runnable 任務* @param delay 延時* @throws InterruptedException*/public void schedule(Runnable runnable,long delay) throws InterruptedException {//根據(jù)傳的參數(shù)構造一個MyTask對象MyTask task=new MyTask(runnable,delay);//將這個MyTask對象阻塞放入隊列中queue.put(task);System.out.println("任務添加成功");}
}//MyTask類,用于封裝任務和執(zhí)行時間
class MyTask implements Comparable<MyTask>{//任務private Runnable runnable;//執(zhí)行時間private long time;public MyTask(Runnable runnable, long delay) {//增強代碼健壯性if(runnable==null){throw new IllegalArgumentException("任務不能為空");}if(delay<0) {throw new IllegalArgumentException("延遲時間不能為負數(shù)");}this.runnable = runnable;//計算出任務的執(zhí)行時間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;}//萬一時間超過了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("任務1");}},0);timer.schedule(new Runnable(){@Overridepublic void run() {System.out.println("任務2");}},0);timer.schedule(new Runnable(){@Overridepublic void run() {System.out.println("任務3");}},0);//timer.schedule(null,-100);//任務加強健壯性}
}
工廠模式
- 先看出現(xiàn)的問題
我們這里造成了重載參數(shù)的相同,但是我們就是要這樣的構造方法我們怎么解決呢?
工廠方法模式。根據(jù)不同的業(yè)務需求定義不同的方法來獲取對象。
線程池
線程池的一些問題
- 什么是線程池
1.線程池就是一次創(chuàng)建多個線程,把這些線程放進一個池中,用的時候從池中取出,用完就還回去 - 為什么要用線程池
我們首先要明白,線程的創(chuàng)建和銷毀都會消耗大量的資源,線程池中的線程當有任務的時候,就會執(zhí)行任務,沒有任務的時候就阻塞等待,并不銷毀線程,線程池最?的好處就是減少每次啟動、銷毀線程的損耗。 - 為什么使用線程池可以提升效率
少量創(chuàng)建,少量銷毀,創(chuàng)建一個線程要分為內核態(tài)和用戶態(tài),用戶態(tài)相當于jvm層面,內核太相當于操作系統(tǒng)層面,當我們在jvm層面創(chuàng)建一個線程,就要在操作系統(tǒng)層面創(chuàng)建對應指令,就會消耗大量資源,消耗線程也如此,所以線程池減少了頻繁的銷毀和創(chuàng)建,用的時候就直接在線程池里面用已經創(chuàng)建多的,從而提升效率。 - 怎么用?
– jdk給我們提供了一組針對不同場景的線程池實例
public static void main(String[] args) {//1.用來處理大量短時間的任務的線程池,如果池沒有可用的線程將創(chuàng)建線程,如果線程空閑60秒將收回并移除緩存ExecutorService cachedThreadpool= Executors.newCachedThreadPool();//2.創(chuàng)建一個操作無界隊列,線程池大小固定的線程池ExecutorService fixedThreadpool= Executors.newFixedThreadPool(5);//可以指定線程數(shù)量//3.創(chuàng)建一個操作無界隊列,只有一個線程的線程池ExecutorService singleThreadExecutor= Executors.newSingleThreadExecutor();//4.創(chuàng)建一個單線程執(zhí)行器,可以加時間給定時間后執(zhí)行或者定期執(zhí)行ScheduledExecutorService singleThreadScheduledExecutor= Executors.newSingleThreadScheduledExecutor();//5.創(chuàng)建一個指定大小的線程池,可以加時間給定時間后執(zhí)行或者定期執(zhí)行ScheduledExecutorService scheduledThreadpool= Executors.newScheduledThreadPool(5);//6.創(chuàng)建一個指定大小(不傳參,為當前機器的cpu核數(shù))的線程池,并行處理任務,不保證處理順序Executors.newWorkStealingPool();
}
Runtime.getRuntime().availableProcessors()
獲取系統(tǒng)的cpu核數(shù)
實現(xiàn)一個線程池
- 先構思思路(先描述,再組織)
- 用Runable描述任務
- 組織管理任務可以使用一個隊列,可以使用阻塞隊列取實現(xiàn)
- 提供一個向隊列的添加任務的方法
- 創(chuàng)建多個線程,掃描隊列里面的任務,有任務時候執(zhí)行,沒有任務時候等待
public class MyExectorService {//定義阻塞隊列阻止任務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(()->{//不停掃描隊列while (true) {try {synchronized (lock){Runnable runable= queue.take();runable.run();}TimeUnit.MILLISECONDS.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}//take()方法會阻塞,直到隊列中有任務});//啟動線程thread.start();}}/*** 提交任務到線程池中* @param runnable 具體的任務* @throws InterruptedException*/public void sumbit(Runnable runnable) throws InterruptedException {if(runnable==null){throw new IllegalArgumentException("任務不能為空");}//把任務加入隊列中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提供的線程池比較固定,也就是說我們不能自己定制,但是我們看底層代碼時發(fā)現(xiàn),這些線程池都是對ThreadPoolExecutor的封裝
- 那我們可以根據(jù)ThreadPoolEecutor創(chuàng)建一個自定義線程池
用現(xiàn)實的兩個例子去模擬線程工作的原理
周末去吃飯
銀行辦理業(yè)務
- 線程池的拒絕策略詳解
- 我們注意一下,3和4是不會拋出異常的,1和2是會拋出異常的,放棄的任務永遠都找不回來,所以指定拒絕策略的時候,要關注任務是不是必須要執(zhí)行,如果必須要執(zhí)行,就指定“返回調用者”,否則選1,3,4一個即可
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í)行任務 "+takeI);}});}}
- 直接拒絕
實際只執(zhí)行幾個后面的都沒執(zhí)行
- 返回給調用者
有一部分代碼返回給調用者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í)行任務 "+takeI);}});}}
- 放棄最早的任務
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í)行任務 "+takeI);}});}}
- 放棄最新的任務
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í)行任務 "+takeI);}});}}
wait和sleep的區(qū)別
1.共同點,讓線程休眠一會
2.從實現(xiàn)使用上來說是兩種不同的方法
wait是Object類的方法,與鎖相關,配合sychronized一起使用,調用wait之后會釋放鎖
sleep是Thread類的方法,與鎖無關
wait可以通過notify和指定直線的方法喚醒,喚醒之后重新競爭鎖資源
sleep只能通過超時時間喚醒
- 補充