Java線程知識
進程是是線程的集合,線程是進程的一條執(zhí)行路徑。(進程就是一個運行的應用程序纺念,使用多線程主要是為了提高程序效率)
創(chuàng)建多線程方法:繼承Thread、實現(xiàn)Runnable想括、匿名內(nèi)部類(new Runnable())陷谱,都是將需要在線程運行的代碼放在run() 方法下。
多線程每個線程運行互不影響主胧。
一般使用實現(xiàn)Runnable方式比繼承Thread方式創(chuàng)建線程好叭首,因為如果的你的類繼承了Thread就不能繼承其他類了习勤,但是一個類可以實現(xiàn)多個接口
守護線程和用戶線程(非守護線程)
Java有兩種線程:用戶線程,守護線程焙格。用戶線程指的是自己定義的線程图毕,主線程停止了用戶線程不會停止,守護線程值得是當進程不存在或主線程停止眷唉,守護線程也會被停止予颤。比如用于垃圾回收的gc線程為守護線程。使用setDaenmon(true)可以將非守護線程設(shè)置為守護線程冬阳。
多線程運行狀態(tài)
?線程從創(chuàng)建蛤虐、運行到結(jié)束總是處于下面五個狀態(tài)之一:新建狀態(tài)、就緒狀態(tài)肝陪、運行狀態(tài)驳庭、阻塞狀態(tài)及死亡狀態(tài)。
新建狀態(tài)
???當用new操作符創(chuàng)建一個線程時氯窍, 例如new Thread(r)饲常,線程還沒有開始運行,此時線程處在新建狀態(tài)狼讨。 當一個線程處于新生狀態(tài)時贝淤,程序還沒有開始運行線程中的代碼
就緒狀態(tài)
一個新創(chuàng)建的線程并不自動開始運行,要執(zhí)行線程政供,必須調(diào)用線程的start()方法播聪。當線程對象調(diào)用start()方法即啟動了線程,start()方法創(chuàng)建線程運行的系統(tǒng)資源布隔,并調(diào)度線程運行run()方法离陶。當start()方法返回后,線程就處于就緒狀態(tài)执泰。
?????處于就緒狀態(tài)的線程并不一定立即運行run()方法枕磁,線程還必須同其他線程競爭CPU時間,只有獲得CPU時間才可以運行線程术吝。因為在單CPU的計算機系統(tǒng)中计济,不可能同時運行多個線程,一個時刻僅有一個線程處于運行狀態(tài)排苍。因此此時可能有多個線程處于就緒狀態(tài)沦寂。對多個處于就緒狀態(tài)的線程是由Java運行時系統(tǒng)的線程調(diào)度程序(thread scheduler)來調(diào)度的。
運行狀態(tài)
當線程獲得CPU時間后淘衙,它才進入運行狀態(tài)传藏,真正開始執(zhí)行run()方法.
阻塞狀態(tài)
?線程運行過程中,可能由于各種原因進入阻塞狀態(tài):
1>線程通過調(diào)用sleep方法進入睡眠狀態(tài);
2>線程調(diào)用一個在I/O上被阻塞的操作毯侦,即該操作在輸入輸出操作完成之前不會返回到它的調(diào)用者哭靖;
3>線程試圖得到一個鎖,而該鎖正被其他線程持有侈离;
4>線程在等待某個觸發(fā)條件试幽;
死亡狀態(tài)
有兩個原因會導致線程死亡:
1) run方法正常退出而自然死亡,
2)一個未捕獲的異常終止了run方法而使線程猝死卦碾。為了確定線程在當前是否存活著(就是要么是可運行的铺坞,要么是被阻塞了),需要使用isAlive方法洲胖。如果是可運行或被阻塞济榨,這個方法返回true;如果線程仍舊是new狀態(tài)且不是可運行的绿映, 或者線程死亡了擒滑,則返回false.
join()使用方法
join()作用是讓其他線程變?yōu)榈却瑃1是一個線程叉弦,t1.join()讓其他線程變?yōu)榈却俪溃钡疆斍皌1線程執(zhí)行完畢,才會釋放卸奉。如果在t2線程中調(diào)用了t1.join()方法,表示t1線程結(jié)束后才會開始執(zhí)行t2線程颖御,此時t2線程處于阻塞狀態(tài)榄棵。原理:
public final synchronized void join(long millis)
? ? throws InterruptedException {
? ? ? ? long base = System.currentTimeMillis();
? ? ? ? long now = 0;
? ? ? ? if (millis < 0) {
? ? ? ? ? ? throw new IllegalArgumentException("timeout value is negative");
? ? ? ? }
? ? ? ? if (millis == 0) {
? ? ? ? ? ? while (isAlive()) {
? ? ? ? ? ? ? ? wait(0);
? ? ? ? ? ? }
? ? ? ? } else {
? ? ? ? ? ? while (isAlive()) {
? ? ? ? ? ? ? ? long delay = millis - now;
? ? ? ? ? ? ? ? if (delay <= 0) {
? ? ? ? ? ? ? ? ? ? break;
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? wait(delay);
? ? ? ? ? ? ? ? now = System.currentTimeMillis() - base;
? ? ? ? ? ? }
? ? ? ? }
? ? }
在t2中調(diào)用t1的join方法會調(diào)用t1的wait()方法,當t1線程結(jié)束(或者到達等待時間)潘拱,t1會調(diào)用notifyAll方法喚醒t2線程疹鳄。
優(yōu)先級
現(xiàn)代操作系統(tǒng)基本采用時分的形式調(diào)度運行的線程,線程分配得到的時間片的多少決定了線程使用處理器資源的多少芦岂,也對應了線程優(yōu)先級這個概念瘪弓。在JAVA線程中,通過一個int priority來控制優(yōu)先級禽最,范圍為1-10腺怯,其中10最高,默認值為5川无。下面是源碼(基于1.8)中關(guān)于priority的一些量和方法呛占。
class PrioritytThread implements Runnable {
?
????? public void run() {
?????????? for (int i = 0; i < 100; i++) {
???????????????? System.out.println(Thread.currentThread().toString()? +"---i:" + i);
?????????? }
????? }
}
?
public class ThreadDemo4 {
?
????? public static void main(String[] args) {
?????????? PrioritytThreadprioritytThread = new PrioritytThread();
?????????? Threadt1 = new Thread(prioritytThread);
?????????? Threadt2 = new Thread(prioritytThread);
?????????? t1.start();
?????????? // 注意設(shè)置了優(yōu)先級, 不代表每次都一定會被執(zhí)行懦趋。 只是CPU調(diào)度會有限分配
?????????? t1.setPriority(10);
?????????? t2.start();
??????????
????? }
?
}
?
Yield方法
Thread.yield()方法的作用:暫停當前正在執(zhí)行的線程晾虑,并執(zhí)行其他線程。(可能沒有效果)
yield()讓當前正在運行的線程回到可運行狀態(tài),以允許具有相同優(yōu)先級的其他線程獲得運行的機會帜篇。因此糙捺,使用yield()的目的是讓具有相同優(yōu)先級的線程之間能夠適當?shù)妮啌Q執(zhí)行。但是笙隙,實際中無法保證yield()達到讓步的目的洪灯,因為,讓步的線程可能被線程調(diào)度程序再次選中逃沿。
結(jié)論:大多數(shù)情況下婴渡,yield()將導致線程從運行狀態(tài)轉(zhuǎn)到可運行狀態(tài),但有可能沒有效果凯亮。