Java 多線(xiàn)程實(shí)例詳解(二)
本文承接上一篇文章《Java多線(xiàn)程實(shí)例詳解(一)》。
四.Java多線(xiàn)程的阻塞狀態(tài)與線(xiàn)程控制
上文已經(jīng)提到Java阻塞的幾種具體類(lèi)型。下面分別看下引起Java線(xiàn)程阻塞的主要方法。
1.join()
join —— 讓一個(gè)線(xiàn)程等待另一個(gè)線(xiàn)程完成才繼續(xù)執(zhí)行。如A線(xiàn)程線(xiàn)程執(zhí)行體中調(diào)用B線(xiàn)程的join()方法,則A線(xiàn)程被阻塞,知道B線(xiàn)程執(zhí)行完為止,A才能得以繼續(xù)執(zhí)行。
public class ThreadTest {
public static void main(String[] args) {
MyRunnable myRunnable = new MyRunnable();
Thread thread = new Thread(myRunnable);
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + " " + i);
if (i == 30) {
thread.start();
try {
thread.join(); // main線(xiàn)程需要等待thread線(xiàn)程執(zhí)行完后才能繼續(xù)執(zhí)行
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
class MyRunnable implements Runnable {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + " " + i);
}
}
}
2.sleep()
sleep —— 讓當(dāng)前的正在執(zhí)行的線(xiàn)程暫停指定的時(shí)間,并進(jìn)入阻塞狀態(tài)。在其睡眠的時(shí)間段內(nèi),該線(xiàn)程由于不是處于就緒狀態(tài),因此不會(huì)得到執(zhí)行的機(jī)會(huì)。即使此時(shí)系統(tǒng)中沒(méi)有任何其他可執(zhí)行的線(xiàn)程,出于sleep()中的線(xiàn)程也不會(huì)執(zhí)行。因此sleep()方法常用來(lái)暫停線(xiàn)程執(zhí)行。
前面有講到,當(dāng)調(diào)用了新建的線(xiàn)程的start()方法后,線(xiàn)程進(jìn)入到就緒狀態(tài),可能會(huì)在接下來(lái)的某個(gè)時(shí)間獲取CPU時(shí)間片得以執(zhí)行,如果希望這個(gè)新線(xiàn)程必然性的立即執(zhí)行,直接調(diào)用原來(lái)線(xiàn)程的sleep(1)即可。
public class ThreadTest {
public static void main(String[] args) {
MyRunnable myRunnable = new MyRunnable();
Thread thread = new Thread(myRunnable);
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + " " + i);
if (i == 30) {
thread.start();
try {
Thread.sleep(1); // 使得thread必然能夠馬上得以執(zhí)行
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
class MyRunnable implements Runnable {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + " " + i);
}
}
}
注:睡一個(gè)毫秒級(jí)夠了,因?yàn)镃PU不會(huì)空閑,會(huì)切換到新建的線(xiàn)程。
3.后臺(tái)線(xiàn)程(Daemon Thread)
概念/目的:后臺(tái)線(xiàn)程主要是為其他線(xiàn)程(相對(duì)可以稱(chēng)之為前臺(tái)線(xiàn)程)提供服務(wù),或“守護(hù)線(xiàn)程”。如JVM中的垃圾回收線(xiàn)程。
生命周期:后臺(tái)線(xiàn)程的生命周期與前臺(tái)線(xiàn)程生命周期有一定關(guān)聯(lián)。主要體現(xiàn)在:當(dāng)所有的前臺(tái)線(xiàn)程都進(jìn)入死亡狀態(tài)時(shí),后臺(tái)線(xiàn)程會(huì)自動(dòng)死亡(其實(shí)這個(gè)也很好理解,因?yàn)楹笈_(tái)線(xiàn)程存在的目的在于為前臺(tái)線(xiàn)程服務(wù)的,既然所有的前臺(tái)線(xiàn)程都死亡了,那它自己還留著有什么用...偉大啊 ! !)。
設(shè)置后臺(tái)線(xiàn)程:調(diào)用Thread對(duì)象的setDaemon(true)方法可以將指定的線(xiàn)程設(shè)置為后臺(tái)線(xiàn)程。
public class ThreadTest {
public static void main(String[] args) {
Thread myThread = new MyThread();
for (int i = 0; i < 100; i++) {
System.out.println("main thread i = " + i);
if (i == 20) {
myThread.setDaemon(true);
myThread.start();
}
}
}
}
class MyThread extends Thread {
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("i = " + i);
try {
Thread.sleep(1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
判斷線(xiàn)程是否是后臺(tái)線(xiàn)程:調(diào)用thread對(duì)象的isDeamon()方法。
注:main線(xiàn)程默認(rèn)是前臺(tái)線(xiàn)程,前臺(tái)線(xiàn)程創(chuàng)建中創(chuàng)建的子線(xiàn)程默認(rèn)是前臺(tái)線(xiàn)程,后臺(tái)線(xiàn)程中創(chuàng)建的線(xiàn)程默認(rèn)是后臺(tái)線(xiàn)程。調(diào)用setDeamon(true)方法將前臺(tái)線(xiàn)程設(shè)置為后臺(tái)線(xiàn)程時(shí),需要在start()方法調(diào)用之前。前天線(xiàn)程都死亡后,JVM通知后臺(tái)線(xiàn)程死亡,但從接收指令到作出響應(yīng),需要一定的時(shí)間。
4.改變線(xiàn)程的優(yōu)先級(jí)/setPriority():
每個(gè)線(xiàn)程在執(zhí)行時(shí)都具有一定的優(yōu)先級(jí),優(yōu)先級(jí)高的線(xiàn)程具有較多的執(zhí)行機(jī)會(huì)。每個(gè)線(xiàn)程默認(rèn)的優(yōu)先級(jí)都與創(chuàng)建它的線(xiàn)程的優(yōu)先級(jí)相同。main線(xiàn)程默認(rèn)具有普通優(yōu)先級(jí)。
設(shè)置線(xiàn)程優(yōu)先級(jí):setPriority(int priorityLevel)。參數(shù)priorityLevel范圍在1-10之間,常用的有如下三個(gè)靜態(tài)常量值:
MAX_PRIORITY:10
MIN_PRIORITY:1
NORM_PRIORITY:5
獲取線(xiàn)程優(yōu)先級(jí):getPriority()。
注:具有較高線(xiàn)程優(yōu)先級(jí)的線(xiàn)程對(duì)象僅表示此線(xiàn)程具有較多的執(zhí)行機(jī)會(huì),而非優(yōu)先執(zhí)行。
public class ThreadTest {
public static void main(String[] args) {
Thread myThread = new MyThread();
for (int i = 0; i < 100; i++) {
System.out.println("main thread i = " + i);
if (i == 20) {
myThread.setPriority(Thread.MAX_PRIORITY);
myThread.start();
}
}
}
}
class MyThread extends Thread {
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("i = " + i);
}
}
}
5.線(xiàn)程讓步:yield()
上一篇博文中已經(jīng)講到了yield()的基本作用,同時(shí),yield()方法還與線(xiàn)程優(yōu)先級(jí)有關(guān),當(dāng)某個(gè)線(xiàn)程調(diào)用yiled()方法從運(yùn)行狀態(tài)轉(zhuǎn)換到就緒狀態(tài)后,CPU從就緒狀態(tài)線(xiàn)程隊(duì)列中只會(huì)選擇與該線(xiàn)程優(yōu)先級(jí)相同或優(yōu)先級(jí)更高的線(xiàn)程去執(zhí)行。
public class ThreadTest {
public static void main(String[] args) {
Thread myThread1 = new MyThread1();
Thread myThread2 = new MyThread2();
myThread1.setPriority(Thread.MAX_PRIORITY);
myThread2.setPriority(Thread.MIN_PRIORITY);
for (int i = 0; i < 100; i++) {
System.out.println("main thread i = " + i);
if (i == 20) {
myThread1.start();
myThread2.start();
Thread.yield();
}
}
}
}
class MyThread1 extends Thread {
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("myThread 1 -- i = " + i);
}
}
}
class MyThread2 extends Thread {
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("myThread 2 -- i = " + i);
}
}
}
系列文章:
java 多線(xiàn)程實(shí)例講解 (一)
Java 多線(xiàn)程實(shí)例詳解(二)
Java 多線(xiàn)程實(shí)例詳解(三)
- Java 多線(xiàn)程實(shí)例講解(一)
- Java Thread多線(xiàn)程詳解及用法解析
- Java 多線(xiàn)程學(xué)習(xí)詳細(xì)總結(jié)
- java 線(xiàn)程創(chuàng)建多線(xiàn)程詳解
- java多線(xiàn)程-同步塊實(shí)例講解
- java 多線(xiàn)程-線(xiàn)程通信實(shí)例講解
- java 多線(xiàn)程-鎖詳解及示例代碼
- java多線(xiàn)程-讀寫(xiě)鎖原理
- Java多線(xiàn)程之異步Future機(jī)制的原理和實(shí)現(xiàn)
- Java 多線(xiàn)程實(shí)例詳解(三)
相關(guān)文章
解決idea spring boot 修改html等不重啟即時(shí)生效的問(wèn)題
這篇文章主要介紹了解決idea spring boot 修改html等不重啟即時(shí)生效的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2021-02-02
Springboot MongoDB實(shí)現(xiàn)自增序列的項(xiàng)目實(shí)踐
在某些特定的業(yè)務(wù)場(chǎng)景下,會(huì)需要使用自增的序列來(lái)維護(hù)數(shù)據(jù),本文主要介紹了Springboot MongoDB實(shí)現(xiàn)自增序列的項(xiàng)目實(shí)踐,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-07-07
springboot中rabbitmq實(shí)現(xiàn)消息可靠性機(jī)制詳解
這篇文章主要介紹了springboot中rabbitmq實(shí)現(xiàn)消息可靠性機(jī)制詳解,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下2021-09-09
Mybatis中l(wèi)ike搭配concat的寫(xiě)法詳解
這篇文章主要介紹了Mybatis中l(wèi)ike搭配concat的寫(xiě)法詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-01-01
windows下java環(huán)境變量的設(shè)置方法
在“系統(tǒng)變量”中,設(shè)置3項(xiàng)屬性,JAVA_HOME,PATH,CLASSPATH(大小寫(xiě)無(wú)所謂),若已存在則點(diǎn)擊“編輯”,不存在則點(diǎn)擊“新建”2013-09-09
Spring中的監(jiān)聽(tīng)器SpringApplicationRunListener詳解
這篇文章主要介紹了Spring中的監(jiān)聽(tīng)器SpringApplicationRunListener詳解,命名我們就可以知道它是一個(gè)監(jiān)聽(tīng)者,分析springboot啟動(dòng)流程我們會(huì)發(fā)現(xiàn),它其實(shí)是用來(lái)在整個(gè)啟動(dòng)流程中接收不同執(zhí)行點(diǎn)事件通知的監(jiān)聽(tīng)者,需要的朋友可以參考下2023-11-11

