婚禮策劃網(wǎng)站模板中文網(wǎng)絡營銷課程學什么
并發(fā)和并行
并發(fā)
在同一時刻,有多個指令在單個CPU上交替執(zhí)行
并行
在同一時刻,有多個指令在多個CPU上同時執(zhí)行
多線程的實現(xiàn)方式
繼承Thread類的方式
注意給線程設置名字,啟動線程等操作
實現(xiàn)Runable的方式
自己創(chuàng)建一個類然后去實現(xiàn)Runable接口,重寫run方法;
為什么會有這個方式?
因為Java只支持單繼承,如果已經(jīng)繼承一個類了,那么就不能繼承第二個類,所以有局限性。
創(chuàng)建一個Thread對象的時候傳入創(chuàng)建的的重寫類,start()開啟線程
問題
在使用自己實現(xiàn)的Runable接口的類的時候,不能直接使用Thread類中的方法,可以通過Thread.currentThread()獲得當前執(zhí)行run()函數(shù)的線程。
利用Callable接口和Future接口方式
為什么要實現(xiàn)Callable接口?因為之前使用的多線程的函數(shù)中并沒有返回值。
1、定義的類實現(xiàn)Callable接口,并重寫call()方法,Callable中的泛型為返回值的類型
2、創(chuàng)建Future類,它是一個抽象類所以應該創(chuàng)建它的子類FutureTask類來管理結(jié)果;創(chuàng)建的時候傳入實現(xiàn)Callable接口的對象。
3、創(chuàng)建Thread類的時候傳入FutureTask的對象
4、執(zhí)行Thread類中的start()方法
4、最后通過FutureTask對象獲得結(jié)果
多線程中常用的成員方法
線程優(yōu)先級
對于搶占式的線程,具有優(yōu)先級。Java中優(yōu)先級為1-10,創(chuàng)建一個線程默認為5;
優(yōu)先級越高,在CPU上執(zhí)行的概率越高。
守護線程
當其他非守護線程執(zhí)行完畢之后,守護線程會陸續(xù)結(jié)束;
換個說法就是,正常線程執(zhí)行完畢了,守護線程就沒有存在的必要了
定義一個非守護線程
定義一個守護線程
創(chuàng)建對象,并設置守護線程
結(jié)果:非守護線程結(jié)束之后,守護線程也結(jié)束了(并不是馬上,存在一定的延遲)
為什么會有守護線程
當把聊天窗關閉之后,傳輸文件的線程就沒有存在的必要了。
禮讓線程
Thread.yield()為線程搶到CPU執(zhí)行權之后,讓出使用權。重新?lián)尵€程。
僅僅會使兩個線程執(zhí)行的更加均勻,并不是絕對均勻,因為還要搶。
插入線程(了解)
有兩個線程A和B,B的線程中獲得A線程的對象,并且A線程的對象調(diào)用join()函數(shù),代表將A線程插入到當前B線程之前;所以A執(zhí)行完畢之后B才執(zhí)行。
線程的生命周期
線程的安全問題
就是3個線程賣票,然后出現(xiàn)賣重復和多余的票的問題。沒啥好解釋的。
同步代碼塊
為了保證操作的唯一性,解決上面線程的安全問題所提出來的
synchronized(鎖對象){}
這里鎖對象可以理解為之前的flag標記,只不過注意是唯一的就行
改進
字節(jié)碼對象可以使用當前類的字節(jié)碼文件對象
同步方法
如果是想鎖住 一整個方法,那么使用同步方法;也就是將synchronized加到方法上,
1、同步方法是鎖住方法里面所有的代碼
2、鎖住的對象不能像上面同步代碼塊那樣能夠自己指定;對于非靜態(tài)的方法中,鎖住的對象為this;對于靜態(tài)的方法為當前類的字節(jié)碼文件對象
3、技巧:對于那些不知道什么東西應該放到同步方法中的問題,可以先寫同步代碼塊,然后將同步代碼塊放到同步方法中。
使用實現(xiàn)Runable的接口的方式進行展示
注意的點
這里面有一個要注意的地方就是,之前使用類去繼承Thread類的時候,里面的ticket是static的;
但是如果是實現(xiàn)Runable接口,那么ticket就不用定義為static;
因為如果繼承Thread的話,我們創(chuàng)建幾個線程就創(chuàng)建幾個Thread,所以里面的ticket為static;
我們?nèi)绻麑崿F(xiàn)Runable的話,我們是創(chuàng)建幾個Thread的時候輸入實現(xiàn)Runable的對象,所以不用為static;
把他改成同步方法的形式
lock鎖
之前的就是很省事,這個lock就是很繁瑣,像是原本OS中精細化上鎖,解鎖。還要考慮其他進程等待其他進程解鎖的邏輯
下面這個函數(shù),會發(fā)生即使票賣出100個,但是程序還是不會停止;因為在100處直接break了,沒有進行解鎖的操作;導致其他線程一直等待鎖
因此改成try catch finally的形式,在finally中執(zhí)行釋放鎖的操作:
死鎖
死鎖是指兩個或兩個以上的進程在執(zhí)行過程中,由于競爭資源或者由于彼此通信而造成的一種阻塞的現(xiàn)象,若無外力作用,它們都將無法推進下去。
生產(chǎn)者消費者(等待喚醒機制)
就是那個一個桌子,一個生產(chǎn)者一個消費者的情形。
生產(chǎn)者
package com.waitandnotify;public class Cook extends Thread{@Overridepublic void run() {synchronized (Desk.lock){while (true){if(Desk.count == 10){break;}if(Desk.flag == 0){Desk.flag = 1;Desk.lock.notifyAll();System.out.println("做了第"+Desk.count+"份");}else {try {Desk.lock.wait();} catch (InterruptedException e) {throw new RuntimeException(e);}}}}}
}
消費者
package com.waitandnotify;public class Foodie extends Thread{@Overridepublic void run() {synchronized (Desk.lock){while(true){if(Desk.flag == 1){System.out.println("正在吃:"+Desk.count);Desk.count++;Desk.flag = 0;//喚醒進程Desk.lock.notifyAll();}else {try {Desk.lock.wait();} catch (InterruptedException e) {throw new RuntimeException(e);}}if(Desk.count == 10){break;}}}}
}
測試類
package com.waitandnotify;public class Demo {public static void main(String[] args) {Cook cook = new Cook();Foodie foodie = new Foodie();cook.start();foodie.start();}
}
等待喚醒機制(阻塞隊列實現(xiàn))
阻塞隊列的繼承結(jié)構(gòu)
放的進程沒有空間的時候會阻塞,取的進程沒有空間的時候會阻塞;這就是通道啊。
ArrayBlockingQueue底層是數(shù)組,所以在創(chuàng)建的時候要指定大小。
創(chuàng)建阻塞隊列
實現(xiàn)生產(chǎn)者
注意阻塞隊列都是一個,所以定義一個成員變量;
注意,queue.put()個queue.take()中才是線程同步的代碼;run函數(shù)中其他部分不是同步的代碼;
所以輸出的地方會出現(xiàn)重復的東西。
消費者
線程的狀態(tài)
線程池
為什么會有線程池?
例子:吃飯,A吃飯要買碗,吃完就把碗摔了;線程創(chuàng)建和消除也是這樣,很費資源。
自定義線程池
核心線程,一直存在;臨時線程為當?shù)却娜蝿照紳M了隊伍,并且有新的任務的時候創(chuàng)建臨時進程;其中定義了臨時的時間,如果超過定義的臨時時間沒有使用臨時進程,那么臨時進程就銷毀。如果提交的任務數(shù)量超過核心線程數(shù)量+臨時線程+隊伍長度;觸發(fā)任務拒絕策略。
任務拒絕策略
多線程額外擴展
看阿偉的文件,不過找不到,直接看八股文吧。