Java基础day20
生活随笔
收集整理的這篇文章主要介紹了
Java基础day20
小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
Java基礎(chǔ)day20
- Java基礎(chǔ)day20-多線程
- 1.實(shí)現(xiàn)多線程
- 1.1進(jìn)程和線程
- 1.2實(shí)現(xiàn)多線程方式一:繼承Thread類(lèi)
- 1.3設(shè)置和獲取線程名稱(chēng)
- 1.4線程優(yōu)先級(jí)
- 1.5線程控制
- 1.6線程的生命周期
- 1.7實(shí)現(xiàn)多線程方式二:實(shí)現(xiàn)Runnable接口
- 2.線程同步
- 2.1賣(mài)票
- 2.2賣(mài)票案例的問(wèn)題
- 2.3同步代碼塊解決數(shù)據(jù)安全問(wèn)題
- 2.4同步方法解決數(shù)據(jù)安全問(wèn)題
- 2.5線程安全的類(lèi)
- 2.6Lock鎖
- 3.生產(chǎn)者消費(fèi)者
- 3.1生產(chǎn)者和消費(fèi)者模式概述
- 3.2生產(chǎn)者和消費(fèi)者案例
Java基礎(chǔ)day20-多線程
1.實(shí)現(xiàn)多線程
1.1進(jìn)程和線程
- 進(jìn)程:是正在運(yùn)行的程序
是系統(tǒng)進(jìn)行資源分配和調(diào)用的獨(dú)立單位
每一個(gè)進(jìn)程都有它自己的內(nèi)存空間和系統(tǒng)資源 - 線程:是進(jìn)程中的單個(gè)順序控制流,是一條執(zhí)行路徑
單線程:一個(gè)進(jìn)程如果只有一條執(zhí)行路徑,則稱(chēng)為單線程程序
多線程:一個(gè)進(jìn)程如果有多條執(zhí)行路徑,則稱(chēng)為多線程程序
1.2實(shí)現(xiàn)多線程方式一:繼承Thread類(lèi)
- 方法介紹
| void run() | 在線程開(kāi)啟后,此方法將被調(diào)用執(zhí)行 |
| void start() | 使此線程開(kāi)始執(zhí)行,Java虛擬機(jī)會(huì)調(diào)用run方法() |
-
實(shí)現(xiàn)步驟
定義一個(gè)類(lèi)MyThread繼承Thread類(lèi) 在MyThread類(lèi)中重寫(xiě)run()方法
創(chuàng)建MyThread類(lèi)的對(duì)象
啟動(dòng)線程 -
代碼演示
- 兩個(gè)小問(wèn)題
為什么要重寫(xiě)run()方法?
? 因?yàn)閞un()是用來(lái)封裝被線程執(zhí)行的代碼
run()方法和start()方法的區(qū)別?
?run():封裝線程執(zhí)行的代碼,直接調(diào)用,相當(dāng)于普通方法的調(diào)用
?start():啟動(dòng)線程;然后由JVM調(diào)用此線程的run()方法
1.3設(shè)置和獲取線程名稱(chēng)
- 方法介紹
| void setName(String name) | 將此線程的名稱(chēng)更改為等于參數(shù)name |
| String getName() | 返回此線程的名稱(chēng) |
| Thread currentThread() | 返回對(duì)當(dāng)前正在執(zhí)行的線程對(duì)象的引用 |
- 代碼演示
1.4線程優(yōu)先級(jí)
- 線程調(diào)度
兩種調(diào)度方式
? 分時(shí)調(diào)度模型:所有線程輪流使用 CPU 的使用權(quán),平均分配每個(gè)線程占用 CPU 的時(shí)間片
? 搶占式調(diào)度模型:優(yōu)先讓優(yōu)先級(jí)高的線程使用 CPU,如果線程的優(yōu)先級(jí)相同,那么會(huì)隨機(jī)選擇一個(gè),優(yōu)先級(jí)高的線程獲取的 CPU 時(shí)間片相對(duì)多一些
Java使用的是搶占式調(diào)度模型
隨機(jī)性
假如計(jì)算機(jī)只有一個(gè) CPU,那么 CPU 在某一個(gè)時(shí)刻只能執(zhí)行一條指令,線程只有得到CPU時(shí)間片,也就是使用權(quán),才可以執(zhí)行指令。所以說(shuō)多線程程序的執(zhí)行是有隨機(jī)性,因?yàn)檎l(shuí)搶到CPU的使用權(quán)是不一定的優(yōu)先級(jí)相關(guān)方法
| final int getPriority() | 返回此線程的優(yōu)先級(jí) |
| final void setPriority(int newPriority) | 更改此線程的優(yōu)先級(jí) 線程默認(rèn)優(yōu)先級(jí)是5;線程優(yōu)先級(jí)的范圍是:1-10 |
1.5線程控制
- 相關(guān)方法
| static void sleep(long millis) | 使當(dāng)前正在執(zhí)行的線程停留(暫停執(zhí)行)指定的毫秒數(shù) |
| void join() | 等待這個(gè)線程死亡 |
| void setDaemon(boolean on) | 將此線程標(biāo)記為守護(hù)線程,當(dāng)運(yùn)行的線程都是守護(hù)線程時(shí),Java虛擬機(jī)將退出 |
- 代碼演示
1.6線程的生命周期
線程一共有五種狀態(tài),線程在各種狀態(tài)之間轉(zhuǎn)換。
1.7實(shí)現(xiàn)多線程方式二:實(shí)現(xiàn)Runnable接口
Thread構(gòu)造方法
| Thread(Runnable target) | 分配一個(gè)新的Thread對(duì)象 |
| Thread(Runnable target, String name) | 分配一個(gè)新的Thread對(duì)象 |
- 實(shí)現(xiàn)步驟
定義一個(gè)類(lèi)MyRunnable實(shí)現(xiàn)Runnable接口
在MyRunnable類(lèi)中重寫(xiě)run()方法
創(chuàng)建MyRunnable類(lèi)的對(duì)象
創(chuàng)建Thread類(lèi)的對(duì)象,把MyRunnable對(duì)象作為構(gòu)造方法的參數(shù)
啟動(dòng)線程 - 代碼演示
- 多線程的實(shí)現(xiàn)方案有兩種
繼承Thread類(lèi)
實(shí)現(xiàn)Runnable接口 - 相比繼承Thread類(lèi),實(shí)現(xiàn)Runnable接口的好處
避免了Java單繼承的局限性
適合多個(gè)相同程序的代碼去處理同一個(gè)資源的情況,把線程和程序的代碼、數(shù)據(jù)有效分離,較好的體現(xiàn)
了面向?qū)ο蟮脑O(shè)計(jì)思想
2.線程同步
2.1賣(mài)票
- 案例需求
某電影院目前正在上映國(guó)產(chǎn)大片,共有100張票,而它有3個(gè)窗口賣(mài)票,請(qǐng)?jiān)O(shè)計(jì)一個(gè)程序模擬該電影院賣(mài)票 - 實(shí)現(xiàn)步驟
- 定義一個(gè)類(lèi)SellTicket實(shí)現(xiàn)Runnable接口,里面定義一個(gè)成員變量:private int tickets = 100;
- 在SellTicket類(lèi)中重寫(xiě)run()方法實(shí)現(xiàn)賣(mài)票,代碼步驟如下
- 判斷票數(shù)大于0,就賣(mài)票,并告知是哪個(gè)窗口賣(mài)的
- 賣(mài)了票之后,總票數(shù)要減1
- 票沒(méi)有了,也可能有人來(lái)問(wèn),所以這里用死循環(huán)讓賣(mài)票的動(dòng)作一直執(zhí)行
- 定義一個(gè)測(cè)試類(lèi)SellTicketDemo,里面有main方法,代碼步驟如下
- 創(chuàng)建SellTicket類(lèi)的對(duì)象
- 創(chuàng)建三個(gè)Thread類(lèi)的對(duì)象,把SellTicket對(duì)象作為構(gòu)造方法的參數(shù),并給出對(duì)應(yīng)的窗口名稱(chēng)
- 啟動(dòng)線程
- 代碼實(shí)現(xiàn)
2.2賣(mài)票案例的問(wèn)題
- 賣(mài)票出現(xiàn)了問(wèn)題
相同的票出現(xiàn)了多次
出現(xiàn)了負(fù)數(shù)的票 - 問(wèn)題產(chǎn)生原因
線程執(zhí)行的隨機(jī)性導(dǎo)致的
2.3同步代碼塊解決數(shù)據(jù)安全問(wèn)題
- 安全問(wèn)題出現(xiàn)的條件
是多線程環(huán)境
有共享數(shù)據(jù)
有多條語(yǔ)句操作共享數(shù)據(jù) - 如何解決多線程安全問(wèn)題呢?
基本思想:讓程序沒(méi)有安全問(wèn)題的環(huán)境 - 怎么實(shí)現(xiàn)呢?
把多條語(yǔ)句操作共享數(shù)據(jù)的代碼給鎖起來(lái),讓任意時(shí)刻只能有一個(gè)線程執(zhí)行即可
Java提供了同步代碼塊的方式來(lái)解決 - 同步代碼塊格式:
synchronized(任意對(duì)象):就相當(dāng)于給代碼加鎖了,任意對(duì)象就可以看成是一把鎖
- 同步的好處和弊端
好處:解決了多線程的數(shù)據(jù)安全問(wèn)題
弊端:當(dāng)線程很多時(shí),因?yàn)槊總€(gè)線程都會(huì)去判斷同步上的鎖,這是很耗費(fèi)資源的,無(wú)形中會(huì)降低程序的運(yùn)行效率 - 代碼演示
2.4同步方法解決數(shù)據(jù)安全問(wèn)題
- 同步方法的格式
同步方法:就是把synchronized關(guān)鍵字加到方法上
同步方法的鎖對(duì)象是什么呢?
this
- 靜態(tài)同步方法
同步靜態(tài)方法:就是把synchronized關(guān)鍵字加到靜態(tài)方法上
同步靜態(tài)方法的鎖對(duì)象是什么呢?
類(lèi)名.class
- 代碼演示
2.5線程安全的類(lèi)
- StringBuffer
- 線程安全,可變的字符序列
- 從版本JDK 5開(kāi)始,被StringBuilder 替代。 通常應(yīng)該使用StringBuilder類(lèi),因?yàn)樗С炙邢嗤牟僮?#xff0c;但它更快,因?yàn)樗粓?zhí)行同步
- Vector
- 從Java 2平臺(tái)v1.2開(kāi)始,該類(lèi)改進(jìn)了List接口,使其成為Java Collections Framework的成員。 與新的集
- 合實(shí)現(xiàn)不同, Vector被同步。 如果不需要線程安全的實(shí)現(xiàn),建議使用ArrayList代替Vector
- Hashtable
- 該類(lèi)實(shí)現(xiàn)了一個(gè)哈希表,它將鍵映射到值。 任何非null對(duì)象都可以用作鍵或者值
- 從Java 2平臺(tái)v1.2開(kāi)始,該類(lèi)進(jìn)行了改進(jìn),實(shí)現(xiàn)了Map接口,使其成為Java Collections Framework的成員。 與新的集合實(shí)現(xiàn)不同, Hashtable被同步。 如果不需要線程安全的實(shí)現(xiàn),建議使用HashMap代替Hashtable
2.6Lock鎖
雖然我們可以理解同步代碼塊和同步方法的鎖對(duì)象問(wèn)題,但是我們并沒(méi)有直接看到在哪里加上了鎖,在哪里釋放了鎖,為了更清晰的表達(dá)如何加鎖和釋放鎖,JDK5以后提供了一個(gè)新的鎖對(duì)象LockLock是接口不能直接實(shí)例化,這里采用它的實(shí)現(xiàn)類(lèi)ReentrantLock來(lái)實(shí)例化- ReentrantLock構(gòu)造方法
| ReentrantLock() | 創(chuàng)建一個(gè)ReentrantLock的實(shí)例 |
- 加鎖解鎖方法
| void lock() | 獲得鎖 |
| void unlock() | 釋放鎖 |
- 代碼演示
3.生產(chǎn)者消費(fèi)者
3.1生產(chǎn)者和消費(fèi)者模式概述
- 概述
生產(chǎn)者消費(fèi)者模式是一個(gè)十分經(jīng)典的多線程協(xié)作的模式,弄懂生產(chǎn)者消費(fèi)者問(wèn)題能夠讓我們對(duì)多線程編程的理解更加深刻。
所謂生產(chǎn)者消費(fèi)者問(wèn)題,實(shí)際上主要是包含了兩類(lèi)線程:
一類(lèi)是生產(chǎn)者線程用于生產(chǎn)數(shù)據(jù)
一類(lèi)是消費(fèi)者線程用于消費(fèi)數(shù)據(jù)
為了解耦生產(chǎn)者和消費(fèi)者的關(guān)系,通常會(huì)采用共享的數(shù)據(jù)區(qū)域,就像是一個(gè)倉(cāng)庫(kù)
生產(chǎn)者生產(chǎn)數(shù)據(jù)之后直接放置在共享數(shù)據(jù)區(qū)中,并不需要關(guān)心消費(fèi)者的行為
消費(fèi)者只需要從共享數(shù)據(jù)區(qū)中去獲取數(shù)據(jù),并不需要關(guān)心生產(chǎn)者的行為
- Object類(lèi)的等待和喚醒方法
| void wait() | 導(dǎo)致當(dāng)前線程等待,直到另一個(gè)線程調(diào)用該對(duì)象的 notify()方法或 notifyAll()方法 |
| void notify() | 喚醒正在等待對(duì)象監(jiān)視器的單個(gè)線程 |
| void notifyAll() | 喚醒正在等待對(duì)象監(jiān)視器的所有線程 |
3.2生產(chǎn)者和消費(fèi)者案例
- 案例需求
生產(chǎn)者消費(fèi)者案例中包含的類(lèi):
奶箱類(lèi)(Box):定義一個(gè)成員變量,表示第x瓶奶,提供存儲(chǔ)牛奶和獲取牛奶的操作
生產(chǎn)者類(lèi)(Producer):實(shí)現(xiàn)Runnable接口,重寫(xiě)run()方法,調(diào)用存儲(chǔ)牛奶的操作
消費(fèi)者類(lèi)(Customer):實(shí)現(xiàn)Runnable接口,重寫(xiě)run()方法,調(diào)用獲取牛奶的操作
測(cè)試類(lèi)(BoxDemo):里面有main方法,main方法中的代碼步驟如下
①創(chuàng)建奶箱對(duì)象,這是共享數(shù)據(jù)區(qū)域
②創(chuàng)建消費(fèi)者創(chuàng)建生產(chǎn)者對(duì)象,把奶箱對(duì)象作為構(gòu)造方法參數(shù)傳遞,因?yàn)樵谶@個(gè)類(lèi)中要調(diào)用存儲(chǔ)牛奶的操作
③對(duì)象,把奶箱對(duì)象作為構(gòu)造方法參數(shù)傳遞,因?yàn)樵谶@個(gè)類(lèi)中要調(diào)用獲取牛奶的操作
④創(chuàng)建2個(gè)線程對(duì)象,分別把生產(chǎn)者對(duì)象和消費(fèi)者對(duì)象作為構(gòu)造方法參數(shù)傳遞
⑤啟動(dòng)線程 - 代碼實(shí)現(xiàn)
總結(jié)
以上是生活随笔為你收集整理的Java基础day20的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Java基础day19
- 下一篇: Java基础day21