java之初学线程
線程
學(xué)習(xí)線程相關(guān)的筆記,前面寫(xiě)過(guò)關(guān)于很多線程的使用,有興趣的可以去了解下
線程
概念理解
- 并發(fā) : 指兩個(gè)或多個(gè)事件在同一個(gè)時(shí)間段內(nèi)發(fā)生(交替執(zhí)行)。
- 并行 : 指兩個(gè)或多個(gè)事件在同一時(shí)刻發(fā)生(同時(shí)發(fā)生)。
- 進(jìn)程 : 是指一個(gè)內(nèi)存中運(yùn)行的應(yīng)用程序,每個(gè)進(jìn)程都有一個(gè)獨(dú)立的內(nèi)存空間,一個(gè)應(yīng)用程序可以同時(shí)運(yùn)行多
個(gè)進(jìn)程;進(jìn)程也是程序的一次執(zhí)行過(guò)程,是系統(tǒng)運(yùn)行程序的基本單位;系統(tǒng)運(yùn)行一個(gè)程序即是一個(gè)進(jìn)程從創(chuàng)
建、運(yùn)行到消亡的過(guò)程。 線程 : 進(jìn)程內(nèi)部的一個(gè)獨(dú)立執(zhí)行單元;一個(gè)進(jìn)程可以同時(shí)并發(fā)的運(yùn)行多個(gè)線程,可以理解為一個(gè)進(jìn)程便相當(dāng)
于一個(gè)單 CPU 操作系統(tǒng),而線程便是這個(gè)系統(tǒng)中運(yùn)行的多個(gè)任務(wù)(一個(gè)程序至少有一個(gè)進(jìn)程,一個(gè)進(jìn)程可以有多個(gè)線程)。線程和進(jìn)程的區(qū)別 :
1.進(jìn)程:有獨(dú)立的內(nèi)存空間,進(jìn)程中的數(shù)據(jù)存放空間(堆空間和棧空間)是獨(dú)立的,至少有一個(gè)線程。
2.線程:堆空間是共享的,棧空間是獨(dú)立的,線程消耗的資源比進(jìn)程小的多。
多線程的原理
從圖中可以看出,線程的啟動(dòng)實(shí)際上是開(kāi)辟了新的空間,這樣的話jvm就可以在U盾謳歌棧之間相互切換,這個(gè)就是多線程的原理.
Runnable接口
Runnable是多線程的祖宗類,多線程都間接或直接的實(shí)現(xiàn)了這個(gè)接口.內(nèi)部只有run方法,所以也可以看出run方法時(shí)多線程的核心.
Thread類
先了解一下Thread類的內(nèi)部方法:
構(gòu)造方法:
- public Thread() :分配一個(gè)新的線程對(duì)象。
- public Thread(String name) :分配一個(gè)指定名字的新的線程對(duì)象。
- public Thread(Runnable target) :分配一個(gè)帶有指定目標(biāo)新的線程對(duì)象。
- public Thread(Runnable target,String name) :分配一個(gè)帶有指定目標(biāo)新的線程對(duì)象并指定名字。
常用方法:
- public String getName() :獲取當(dāng)前線程名稱。
- public void start() :導(dǎo)致此線程開(kāi)始執(zhí)行; Java虛擬機(jī)調(diào)用此線程的run方法。
- public void run() :此線程要執(zhí)行的任務(wù)在此處定義代碼。
- public static void sleep(long millis) :使當(dāng)前正在執(zhí)行的線程以指定的毫秒數(shù)暫停(暫時(shí)停止執(zhí)行)。
- public static Thread currentThread() :返回對(duì)當(dāng)前正在執(zhí)行的線程對(duì)象的引用。
使用Thread來(lái)創(chuàng)建線程
void start() :導(dǎo)致此線程開(kāi)始執(zhí)行; Java虛擬機(jī)調(diào)用此線程的run方法。結(jié)果是兩個(gè)線程并發(fā)執(zhí)行,當(dāng)前線程(main)
和另一個(gè)線程(創(chuàng)建的新線程,執(zhí)行其run方法),多次啟動(dòng)一個(gè)線程是非法的.特別當(dāng)線程已經(jīng)結(jié)束后,不能重新啟動(dòng).java程序
是搶占式調(diào)度,哪個(gè)線程優(yōu)先級(jí)高,哪個(gè)線程先執(zhí)行;同一個(gè)優(yōu)先級(jí),隨機(jī)選擇一個(gè).
獲取線程名稱
獲取線程的名稱有兩種方法:
- 使用getName()獲取線程名稱,這個(gè)需要使用Thread類的子類對(duì)象來(lái)調(diào)用.
- 使用Thread.currentThread().getName()獲取線程名稱(推薦使用)
設(shè)置線程名稱
設(shè)置線程的名稱也有兩種方式:
- 使用setName()方法設(shè)置線程名稱,也是需要Thread類或者子類的對(duì)象調(diào)用.
- 使用構(gòu)造方法,可以使用有參構(gòu)造來(lái)設(shè)置線程名稱.
Runnable接口
使用線程類對(duì)象調(diào)用start方法啟動(dòng)線程.
這個(gè)過(guò)程中需要注意的是第四步,需要使用public Thread(Runnable target) :分配一個(gè)帶有指定目標(biāo)新的線程對(duì)象。
public Thread(Runnable target,String name) :分配一個(gè)帶有指定目標(biāo)新的線程對(duì)象并指定名字。這兩個(gè)構(gòu)造方法.
創(chuàng)建線程的方式
實(shí)現(xiàn)Runnable接口
/*** 使用實(shí)現(xiàn)Runnable接口實(shí)現(xiàn)多線程** @author WZLOVE* @create 2018-07-16 19:46*/public class MyRunnable implements Runnable{@Overridepublic void run() {for (int i = 0; i < 100; i++) {System.out.println(Thread.currentThread().getName() + ":" + i);}}}繼承Thread類
/*** 使用繼承實(shí)現(xiàn)多線程** @author WZLOVE* @create 2018-07-16 19:47*/public class MyThread extends Thread{public MyThread() {}public MyThread(String name) {super(name);}@Overridepublic void run() {for (int i = 0; i < 100; i++) {System.out.println(getName() + ":" + i);}}}不同的方法實(shí)現(xiàn)多線程,創(chuàng)建對(duì)象使用的方式也不同:
/*** @author WZLOVE* @create 2018-07-16 19:45*/public class ThreadDemo {public static void main(String[] args) {// 繼承創(chuàng)建對(duì)象相對(duì)簡(jiǎn)單MyThread mt = new MyThread("繼承");mt.start();// 實(shí)現(xiàn)接口創(chuàng)建對(duì)象// 創(chuàng)建自定義類對(duì)象MyRunnable mr = new MyRunnable();// 創(chuàng)建線程對(duì)象Thread thread = new Thread(mr,"實(shí)現(xiàn)接口");thread.start();}}注意點(diǎn):
1.實(shí)際上,Thread類也實(shí)現(xiàn)了Runnable接口.
2.所有的多線程代碼都在run方法里面
3.所有的多線程代碼都是通過(guò)運(yùn)行Thread的start()方法來(lái)運(yùn)行的
4.Runnable對(duì)象僅僅作為T(mén)hread對(duì)象的target,Runnable實(shí)現(xiàn)類里包含的run()方法僅作為線程執(zhí)行體。
而實(shí)際的線程對(duì)象依然是Thread實(shí)例,只是該Thread線程負(fù)責(zé)執(zhí)行其target的run()方法。
實(shí)現(xiàn)Runnable接口與繼承Thread類的不同點(diǎn)
使用接口比類是更有優(yōu)勢(shì)的:
- 可以避免java中的單繼承的局限性。
- 增加程序的健壯性,實(shí)現(xiàn)解耦操作,代碼可以被多個(gè)線程共享,代碼和線程獨(dú)立(任務(wù)類和線程類進(jìn)行分離,解耦)。
- 但是實(shí)現(xiàn)接口不能直接使用Thread類的方法,但是可以通過(guò)獲取當(dāng)前線程對(duì)象進(jìn)行調(diào)用方法.
- 適合多個(gè)相同的程序代碼的線程去共享同一個(gè)資源。
- 線程池只能放入實(shí)現(xiàn)Runable或Callable類線程,不能直接放入繼承Thread的類。
線程的安全問(wèn)題的產(chǎn)生
線程的安全問(wèn)題的產(chǎn)生是由于多個(gè)線程對(duì)共享資源的訪問(wèn).簡(jiǎn)單的說(shuō)線程安全問(wèn)題都是由全局變量及靜態(tài)變量引起的。
若每個(gè)線程中對(duì)全局變量、靜態(tài)變量只有讀操作,而無(wú)寫(xiě)操作,一般來(lái)說(shuō),這個(gè)全局變量是線程安全的;
若有多個(gè)線程同時(shí)執(zhí)行寫(xiě)操作,一般都需要考慮線程同步,否則的話就可能影響線程安全。
買電影票的例子(出現(xiàn)安全問(wèn)題,運(yùn)行一下):
上面的情況就會(huì)出現(xiàn)線程安全問(wèn)題.
線程的安全問(wèn)題的解決
使用同步解決線程的安全問(wèn)題.
- 同步代碼塊
- 同步方法
- lock鎖機(jī)制
1.同步代碼塊
格式 :
// 同步對(duì)象可一是任意對(duì)象,推薦使用thissynchronized(同步對(duì)象){可能出現(xiàn)同步問(wèn)題的代碼}鎖對(duì)象可以是任意對(duì)象,但是鎖對(duì)象必須唯一.
2.同步方法
格式:
// 同步方法也是有鎖對(duì)象的,也就是當(dāng)前對(duì)象this修飾符 synchronized 返回值類型 方法名(參數(shù)列表){可能出現(xiàn)同步問(wèn)題的代碼}需要注意的是靜態(tài)同步方法內(nèi)的同步鎖不是this(因?yàn)殪o態(tài)代碼的執(zhí)行在this之前產(chǎn)生),而是類的字節(jié)碼對(duì)象,也就是(類名.class)
3.Lock鎖機(jī)制
- public void lock() :加同步鎖。
- public void unlock() :釋放同步鎖。
使用步驟:
線程狀態(tài)的概述
| new()新建 | 線程剛被創(chuàng)建,但是并未啟動(dòng)。還沒(méi)調(diào)用start方法。 |
| Runnable(可運(yùn)行) | 線程可以在java虛擬機(jī)中運(yùn)行的狀態(tài),可能正在運(yùn)行自己代碼,也可能沒(méi)有,這取決于操 作系統(tǒng)處理器。 |
| Blocked(鎖阻塞) | 當(dāng)一個(gè)線程試圖獲取一個(gè)對(duì)象鎖,而該對(duì)象鎖被其他的線程持有,則該線程進(jìn)入Blocked狀 態(tài);當(dāng)該線程持有鎖時(shí),該線程將變成Runnable狀態(tài)。 |
| Waiting(無(wú)限等待) | 一個(gè)線程在等待另一個(gè)線程執(zhí)行一個(gè)(喚醒)動(dòng)作時(shí),該線程進(jìn)入Waiting狀態(tài)。進(jìn)入這個(gè) 狀態(tài)后是不能自動(dòng)喚醒的,必須等待另一個(gè)線程調(diào)用notify或者notifyAll方法才能夠喚醒。 |
| Timed Waiting(計(jì)時(shí)等待) | 同waiting狀態(tài),有幾個(gè)方法有超時(shí)參數(shù),調(diào)用他們將進(jìn)入Timed Waiting狀態(tài)。這一狀態(tài) 將一直保持到超時(shí)期滿或者接收到喚醒通知。帶有超時(shí)參數(shù)的常用方法有Thread.sleep 、 Object.wait。 |
| Teminated(被終止) | 因?yàn)閞un方法正常退出而死亡,或者因?yàn)闆](méi)有捕獲的異常終止了run方法而死亡。 |
狀態(tài)圖:
等待喚醒機(jī)制
Object類中的四個(gè)方法:
- wait() : 使線程處于等待狀態(tài),等待著其他的線程喚醒
- wait(long millis) : 使線程處于等待狀態(tài), 等待著其他的線程喚醒/等待時(shí)間到達(dá)
- notify() : 喚醒其他的單個(gè)等待的線程
- notifyAll() : 喚醒其他的所有等待的線程
sleep()與wait()
- sleep:Thread類中的靜態(tài)方法,休眠指定的時(shí)間,在指定時(shí)間后自動(dòng)喚醒,不回釋放鎖對(duì)象
- wait : Object類中的方法,無(wú)限等待,等待其他線程的喚醒,必須釋放鎖對(duì)象
轉(zhuǎn)載于:https://www.cnblogs.com/wadmwz/p/9325466.html
總結(jié)
- 上一篇: 16.1 用auth0服务 实现用登录和
- 下一篇: 初学SpringMVC,使用MVC进行文