java厨房_Java多线程基础
目錄:
進(jìn)程和線程
為什么使用多線程?
多線程的創(chuàng)建方式
Runnable與Thread兩種方式比較
start()與run()方法
線程的生命周期/狀態(tài)轉(zhuǎn)換
常用方法使用與解讀
線程的優(yōu)先級(jí)
守護(hù)線程
1、進(jìn)程和線程
進(jìn)程(Process)是計(jì)算機(jī)中的程序關(guān)于某數(shù)據(jù)集合上的一次運(yùn)行活動(dòng),是系統(tǒng)進(jìn)行資源分配和調(diào)度的基本單位,是操作系統(tǒng)結(jié)構(gòu)的基礎(chǔ)。在早期面向進(jìn)程設(shè)計(jì)的計(jì)算機(jī)結(jié)構(gòu)中,進(jìn)程是程序的基本執(zhí)行實(shí)體;在當(dāng)代面向線程設(shè)計(jì)的計(jì)算機(jī)結(jié)構(gòu)中,進(jìn)程是線程的容器。程序是指令、數(shù)據(jù)及其組織形式的描述,進(jìn)程是程序的實(shí)體。
一個(gè)程序就是一個(gè)進(jìn)程,而一個(gè)程序中的多個(gè)任務(wù)則被稱為線程。
進(jìn)程是表示資源分配的基本單位,線程是進(jìn)程中執(zhí)行運(yùn)算的最小單位,亦是調(diào)度運(yùn)行的基本單位。
2、為什么要使用多線程?
提升效率,提升性能;發(fā)揮多核CPU的優(yōu)勢(shì)。
防止阻塞:從程序運(yùn)行效率的角度來(lái)看,單核CPU不但不會(huì)發(fā)揮出多線程的優(yōu)勢(shì),反而會(huì)因?yàn)樵趩魏薈PU上運(yùn)行多線程導(dǎo)致線程上下文的切換,而降低程序整體的效率。但是單核CPU我們還是要應(yīng)用多線程,就是為了防止阻塞。試想,如果單核CPU使用單線程,那么只要這個(gè)線程阻塞了,比方說(shuō)遠(yuǎn)程讀取某個(gè)數(shù)據(jù)吧,對(duì)端遲遲未返回又沒(méi)有設(shè)置超時(shí)時(shí)間,那么你的整個(gè)程序在數(shù)據(jù)返回回來(lái)之前就停止運(yùn)行了。多線程可以防止這個(gè)問(wèn)題,多條線程同時(shí)運(yùn)行,哪怕一條線程的代碼執(zhí)行讀取數(shù)據(jù)阻塞,也不會(huì)影響其它任務(wù)的執(zhí)行。
3、多線程的創(chuàng)建方式[細(xì)分為5種]
繼承Thread類,重寫run方法。new一個(gè)實(shí)例。
實(shí)現(xiàn)Runnable接口,重寫run方法。作為參數(shù)傳入Thread thread = new Thread(參數(shù));來(lái)創(chuàng)建。
匿名內(nèi)部類的方式(與實(shí)現(xiàn)Runnable接口一樣,只是形式不同 )
通過(guò)并發(fā)包中Callable、Callback來(lái)創(chuàng)建
通過(guò)線程池來(lái)創(chuàng)建線程
4、Runnable與Thread兩種方式比較
繼承Thread不必多說(shuō),繼承后重寫run方法。new一個(gè)實(shí)例調(diào)用start()方法就可以了。
兩者非要比較的話,使用Runnable較好,因?yàn)閷?shí)現(xiàn)接口的方式比繼承類的方式更靈活,也能減少程序之間的耦合度,面向接口編程也是設(shè)計(jì)模式6大原則的核心。
這里重點(diǎn)看下實(shí)現(xiàn)Runnable接口創(chuàng)建線程,實(shí)現(xiàn)Runnable接口實(shí)際上還是需要Thread類來(lái)創(chuàng)建線程,我們來(lái)看下Thread的構(gòu)造方法API:
另外需要說(shuō)明的是Thread.java類也實(shí)現(xiàn)了Runnable接口,如下圖:
那也就意味著Thread的構(gòu)造函數(shù)不僅可以傳入Runnable接口的對(duì)象還可以傳入一個(gè)Thread類的對(duì)象,這樣就可以將一個(gè)Thread類的run()方法交由其他線程來(lái)調(diào)用。
5、start()與run()方法
只有調(diào)用了start()方法,才會(huì)表現(xiàn)出多線程的特性,不同線程的run()方法里面的代碼交替執(zhí)行。如果只是調(diào)用run()方法,那么代碼還是同步執(zhí)行的,必須等待一個(gè)線程的run()方法里面的代碼全部執(zhí)行完畢之后,另外一個(gè)線程才可以執(zhí)行其run()方法里面的代碼。
6、線程的生命周期/狀態(tài)轉(zhuǎn)換
生命周期的五種狀態(tài)【簡(jiǎn)單版文字描述】:
新建(new Thread)當(dāng)創(chuàng)建Thread類的一個(gè)實(shí)例(對(duì)象)時(shí),此線程進(jìn)入新建狀態(tài)(未被啟動(dòng))。
例如:Thread t1=new Thread();
就緒(runnable)線程已經(jīng)被啟動(dòng),正在等待被分配給CPU時(shí)間片,也就是說(shuō)此時(shí)線程正在就緒隊(duì)列中排隊(duì)等候得到CPU資源。例如:t1.start();
運(yùn)行(running)線程獲得CPU資源正在執(zhí)行任務(wù)(run()方法),此時(shí)除非此線程自動(dòng)放棄CPU資源或者有優(yōu)先級(jí)更高的線程進(jìn)入,線程將一直運(yùn)行到結(jié)束。
死亡(dead)
當(dāng)線程執(zhí)行完畢或被其它線程殺死,線程就進(jìn)入死亡狀態(tài),這時(shí)線程不可能再進(jìn)入就緒狀態(tài)等待執(zhí)行。
自然終止:正常運(yùn)行run()方法后終止
異常終止:調(diào)用stop()方法讓一個(gè)線程終止運(yùn)行,這里說(shuō)明下stop()方法雖然可以停止線程,但這個(gè)方法線程不安全,在新版本的java中已經(jīng)被廢棄。
堵塞(blocked)
由于某種原因?qū)е抡谶\(yùn)行的線程讓出CPU并暫停自己的執(zhí)行,即進(jìn)入堵塞狀態(tài)。
正在睡眠:用sleep(long t) 方法可使線程進(jìn)入睡眠方式。一個(gè)睡眠著的線程在指定的時(shí)間過(guò)去可進(jìn)入就緒狀態(tài)。
正在等待:調(diào)用wait()方法。(調(diào)用notify()方法回到就緒狀態(tài))
被另一個(gè)線程所阻塞:調(diào)用suspend()方法。(調(diào)用resume()方法恢復(fù))廢棄
更全的線程狀態(tài)轉(zhuǎn)換圖如下:
7、常用方法使用與解讀
start():使線程進(jìn)入“就緒”(可運(yùn)行)狀態(tài),通知jvm開(kāi)啟新線程來(lái)執(zhí)行run方法。如果多次調(diào)用了start()方法,則會(huì)出現(xiàn)Exception in thread "main" java.lang.IllegalThreadStateException因?yàn)閟tart會(huì)修改當(dāng)前線程的狀態(tài)變量,只有狀態(tài)變量是初始值時(shí)才能start。
線程中斷相關(guān):
stop()【廢棄】:停止一個(gè)線程,可以使用Thread.stop()方法,但是他是不安全的,而且已經(jīng)被廢棄了呢。調(diào)用的時(shí)候還會(huì)拋出一個(gè)java.lang.ThreadDeath異常 ,但是通常情況下,此異常不需要顯示的捕捉。廢棄原因:因?yàn)閺?qiáng)制讓線程停止則有可能使一些請(qǐng)理性的工作得不到完成。另外情況就是對(duì)鎖定的對(duì)象進(jìn)行了“解鎖”,導(dǎo)致 數(shù)據(jù)得不到同步的處理,出現(xiàn)數(shù)據(jù)不一致的問(wèn)題。
interrupt():大多數(shù)停止一個(gè)線程的操作是使用Thread.interrupt()方法,盡管名義為“中止,停止”但這個(gè)方法不會(huì)終止一個(gè)正在運(yùn)行的線程,只是打了一個(gè)標(biāo)記,還需要加入一個(gè)判斷才可以完成線程的停止。Thread.java中提供了兩個(gè)方法:
this.interrupted():測(cè)試當(dāng)前線程是否已經(jīng)中斷。public static boolean interrupted()
this.isInterrupted():測(cè)試線程是否已經(jīng)中斷。public boolean isInterrupted()
具體終止線程操作(來(lái)源網(wǎng)絡(luò)):https://www.cnblogs.com/jenkov/p/juc_interrupt.html
其中的return停止線程可以的,但是還是建議使用“拋異常”的方法來(lái)實(shí)現(xiàn)線程的停止,因?yàn)樵赾atch塊中還可以將異常上拋,使線程停止的事件得以傳播。
另外這兩個(gè)方法的區(qū)別:
interrupted()無(wú)論怎么都是指正在運(yùn)行的線程。而isInterrupted()就是表示指定的線程咯。
interrupted()會(huì)清除標(biāo)記,什么意思呢?就是調(diào)用interrupt()給當(dāng)前線程打一個(gè)中斷標(biāo)記,第一次用interrupted()會(huì)返回true但是 如果不處理,之后的調(diào)用都會(huì)返回false因?yàn)樗阎袛鄻?biāo)記給清了。
暫停線程相關(guān):
suspend()與resume()【廢棄】:一個(gè)暫停線程,一個(gè)恢復(fù)線程到運(yùn)行狀態(tài)。suspend()會(huì)暫停線程,假如當(dāng)前線程為關(guān)鍵數(shù)據(jù)結(jié)構(gòu)加鎖 這時(shí)被掛起那么鎖將無(wú)法釋放對(duì)其他線程來(lái)說(shuō)造成死鎖。同時(shí)也會(huì)因?yàn)榫€程的暫停出現(xiàn)數(shù)據(jù)不同步的現(xiàn)象。
currentThread():該方法返回代碼段正在被那個(gè)線程調(diào)用的信息。
isAlive():判斷當(dāng)前線程是否處于活動(dòng)的狀態(tài)。活動(dòng)狀態(tài)是指線程已經(jīng)啟動(dòng)尚未終止的狀態(tài)。線程處于正在運(yùn)行或準(zhǔn)備開(kāi)始運(yùn)行的狀態(tài),就認(rèn)為線程是“存活”的。
sleep():在指定毫秒內(nèi)讓當(dāng)前正在執(zhí)行的線程休眠。這個(gè)“正在執(zhí)行的線程”是指this.currentThread()返回的線程。
getId():取得線程的唯一標(biāo)識(shí)。這個(gè)是自動(dòng)分配的,且是唯一的。
yield():放棄當(dāng)前的CUP資源,將它讓給其他的任務(wù)去占用CPU執(zhí)行時(shí)間。但是放棄的時(shí)間不確定,有可能剛剛放棄,馬上又獲得CPU時(shí)間片。
8、線程的優(yōu)先級(jí)
線程可以劃分優(yōu)先級(jí),CPU優(yōu)先執(zhí)行優(yōu)先級(jí)較高的線程對(duì)象中的任務(wù)。
設(shè)置線程的優(yōu)先級(jí)使用setPriority()方法,該方法的源碼如下:
/**
* Changes the priority of this thread.
*
* First the checkAccess method of this thread is called
* with no arguments. This may result in throwing a
* SecurityException.
*
* Otherwise, the priority of this thread is set to the smaller of
* the specified newPriority and the maximum permitted
* priority of the thread's thread group.
*
* @param newPriority priority to set this thread to
* @exception IllegalArgumentException If the priority is not in the
* range MIN_PRIORITY to
* MAX_PRIORITY.
* @exception SecurityException if the current thread cannot modify
* this thread.
* @see #getPriority
* @see #checkAccess()
* @see #getThreadGroup()
* @see #MAX_PRIORITY
* @see #MIN_PRIORITY
* @see ThreadGroup#getMaxPriority()
*/
public final void setPriority(int newPriority) {
ThreadGroup g;
checkAccess();
if (newPriority > MAX_PRIORITY || newPriority < MIN_PRIORITY) {
throw new IllegalArgumentException();
}
if((g = getThreadGroup()) != null) {
if (newPriority > g.getMaxPriority()) {
newPriority = g.getMaxPriority();
}
setPriority0(priority = newPriority);
}
}
在Java中,線程的優(yōu)先級(jí)分為【1~10】10個(gè)等級(jí),從代碼中我們也能看到,如果小于1或者大于10,則會(huì)拋出
IllegalArgumentException異常。
JDK中使用三個(gè)常量來(lái)預(yù)定義線程的優(yōu)先級(jí):
/**
* The minimum priority that a thread can have.
*/
public final static int MIN_PRIORITY = 1;
/**
* The default priority that is assigned to a thread.
*/
public final static int NORM_PRIORITY = 5;
/**
* The maximum priority that a thread can have.
*/
public final static int MAX_PRIORITY = 10;
線程優(yōu)先級(jí)的特性:
繼承性:比如A線程啟動(dòng)B線程,則B線程的優(yōu)先級(jí)與A是一樣的。設(shè)置A線程的優(yōu)先級(jí)為6那么B線程也就是6。
規(guī)則性:線程優(yōu)先級(jí)等級(jí)差距很大的時(shí)候,誰(shuí)先執(zhí)行完與代碼的調(diào)用順序無(wú)關(guān)。CPU盡量將資源讓給優(yōu)先級(jí)比較高的線程
隨機(jī)性:優(yōu)先級(jí)高的線程不一定每次都先執(zhí)行完。優(yōu)先級(jí)相近越能看出隨機(jī)性。
優(yōu)先級(jí)高的代碼執(zhí)行速度更快?
這是一個(gè)相對(duì)的問(wèn)題,因?yàn)閮?yōu)先級(jí)高的會(huì)占用更多的時(shí)間片,相同的任務(wù)量能夠更早的完成。或者說(shuō)相同時(shí)間內(nèi)可以完成更多的操作。但實(shí)際上CPU處理的速度是一樣的。
9、守護(hù)線程
守護(hù)線程是一種特殊的線程,任何一個(gè)守護(hù)線程都是整個(gè)(沒(méi)錯(cuò)是整個(gè))JVM中所有非守護(hù)線程的“保姆”,只要當(dāng)前JVM實(shí)例中存在任何一個(gè)非守護(hù)線程沒(méi)有結(jié)束,守護(hù)線程就在工作,只有當(dāng)最后一個(gè)非守護(hù)線程結(jié)束時(shí),守護(hù)線程才能隨著JVM一同結(jié)束工作。Daemon的作用就是為其他線程的運(yùn)行提供便利服務(wù),守護(hù)線程最經(jīng)典的應(yīng)用就是GC(垃圾回收器)。
讓一個(gè)線程成為守護(hù)線程的方法是setDaemon(true);
總結(jié)
以上是生活随笔為你收集整理的java厨房_Java多线程基础的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 期中总结
- 下一篇: java打印整个向量_Java中Vect