帶你聊聊 Java 并發(fā)編程之線程基礎(chǔ)

01力奋、簡介

百丈高樓平地起,要想學(xué)好多線程砸捏,首先還是的了解一下線程的基礎(chǔ),這邊文章將帶著大家來了解一下線程的基礎(chǔ)知識隙赁。

02垦藏、線程的創(chuàng)建方式

實現(xiàn) Runnable 接口

繼承 Thread 類

實現(xiàn) Callable 接口通過 FutureTask 包裝器來創(chuàng)建線程

通過線程池創(chuàng)建線程

下面將用線程池和 Callable 的方式來創(chuàng)建線程

public class CallableDemo implements Callable<String> {

? ? @Override

? ? public String call() throws Exception {

? ? ? ? int a=1;

? ? ? ? int b=2;

? ? ? ? System. out .println(a+b);

? ? ? ? return "執(zhí)行結(jié)果:"+(a+b);

? ? }

? ? public static void main(String[] args) throws ExecutionException, InterruptedException {

? ? ? ? //創(chuàng)建一個可重用固定線程數(shù)為1的線程池

? ? ? ? ExecutorService executorService = Executors.newFixedThreadPool (1);

? ? ? ? CallableDemo callableDemo=new CallableDemo();

? ? ? ? //執(zhí)行線程,用future來接收線程的返回值

? ? ? ? Future<String> future = executorService.submit(callableDemo);

? ? ? ? //打印線程的返回值

? ? ? ? System. out .println(future.get());

? ? ? ? executorService.shutdown();

? ? }

}

執(zhí)行結(jié)果

3

執(zhí)行結(jié)果:3

03、線程的生命周期

NEW:初始狀態(tài)伞访,線程被構(gòu)建掂骏,但是還沒有調(diào)用 start 方法。

RUNNABLED:運行狀態(tài)厚掷,JAVA 線程把操作系統(tǒng)中的就緒和運行兩種狀態(tài)統(tǒng)一稱為“運行中”弟灼。調(diào)用線程的 start() 方法使線程進(jìn)入就緒狀態(tài)级解。

BLOCKED:阻塞狀態(tài),表示線程進(jìn)入等待狀態(tài),也就是線程因為某種原因放棄了 CPU 使用權(quán)田绑。比如訪問 synchronized 關(guān)鍵字修飾的方法勤哗,沒有獲得對象鎖。

Waiting :等待狀態(tài)掩驱,比如調(diào)用 wait() 方法芒划。

TIME_WAITING:超時等待狀態(tài),超時以后自動返回欧穴。比如調(diào)用 sleep(long millis) 方法

TERMINATED:終止?fàn)顟B(tài)民逼,表示當(dāng)前線程執(zhí)行完畢。

看下源碼:

public enum State {

? ? ? ? NEW,

? ? ? ? RUNNABLE,

? ? ? ? BLOCKED,

? ? ? ? WAITING,

? ? ? ? TIMED_WAITING,

? ? ? ? TERMINATED;

}

04涮帘、線程的優(yōu)先級

線程的最小優(yōu)先級:1

線程的最大優(yōu)先級:10

線程的默認(rèn)優(yōu)先級:5

通過調(diào)用 getPriority() 和 setPriority(int newPriority) 方法來獲得和設(shè)置線程的優(yōu)先級

看下源碼:

/**

? ? * 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;

看下代碼:

public class ThreadA extends Thread {

? ? public static void main(String[] args) {

? ? ? ? ThreadA a = new ThreadA();

? ? ? ? System.out.println(a.getPriority());//5

? ? ? ? a.setPriority(8);

? ? ? ? System.out.println(a.getPriority());//8

? ? }

}

線程優(yōu)先級特性:

繼承性:比如 A 線程啟動 B 線程拼苍,則B線程的優(yōu)先級與 A 是一樣的。

規(guī)則性:高優(yōu)先級的線程總是大部分先執(zhí)行完调缨,但不代表高優(yōu)先級線程全部先執(zhí)行完疮鲫。

隨機性:優(yōu)先級較高的線程不一定每一次都先執(zhí)行完。

05同蜻、線程的停止

stop() 方法棚点,這個方法已經(jīng)標(biāo)記為過時了,強制停止線程湾蔓,相當(dāng)于 kill -9瘫析。

interrupt() 方法,優(yōu)雅的停止線程默责。告訴線程可以停止了贬循,至于線程什么時候停止,取決于線程自身桃序。

看下停止線程的代碼:

public class InterruptDemo {

? ? private static int i ;

? ? public static void main(String[] args) throws InterruptedException {

? ? ? ? Thread thread = new Thread(() -> {

? ? ? ? ? ? //默認(rèn)情況下isInterrupted 返回 false杖虾、通過 thread.interrupt 變成了 true

? ? ? ? ? ? while (!Thread.currentThread().isInterrupted()) {

? ? ? ? ? ? ? ? i++;

? ? ? ? ? ? }

? ? ? ? ? ? System.out.println("Num:" + i);

? ? ? ? }, "interruptDemo");

? ? ? ? thread.start();

? ? ? ? TimeUnit.SECONDS.sleep(1);

? ? ? ? thread.interrupt(); //不加這句,thread線程不會停止

? ? }

}

看上面這段代碼,主線程 main 方法調(diào)用 thread線程的 interrupt() 方法媒熊,就是告訴 thread 線程奇适,你可以停止了(其實是將 thread 線程的一個屬性設(shè)置為了 true ),然后 thread 線程通過 isInterrupted() 方法獲取這個屬性來判斷是否設(shè)置為了 true芦鳍。這里我再舉一個例子來說明一下嚷往,

看代碼:

public class ThreadDemo {

? ? private volatile static Boolean interrupt = false ;

? ? private static int i ;

? ? public static void main(String[] args) throws InterruptedException {

? ? ? ? Thread thread = new Thread(() -> {

? ? ? ? ? ? while (!interrupt) {

? ? ? ? ? ? ? ? i++;

? ? ? ? ? ? }

? ? ? ? ? ? System.out.println("Num:" + i);

? ? ? ? }, "ThreadDemo");

? ? ? ? thread.start();

? ? ? ? TimeUnit.SECONDS.sleep(1);

? ? ? ? interrupt = true;

? ? }

}

是不是很相似,再簡單總結(jié)一下:

當(dāng)其他線程通過調(diào)用當(dāng)前線程的 interrupt 方法柠衅,表示向當(dāng)前線程打個招呼皮仁,告訴他可以中斷線程的執(zhí)行了,并不會立即中斷線程,至于什么時候中斷贷祈,取決于當(dāng)前線程自己趋急。

線程通過檢查自身是否被中斷來進(jìn)行相應(yīng),可以通過 isInterrupted() 來判斷是否被中斷势誊。

這種通過標(biāo)識符來實現(xiàn)中斷操作的方式能夠使線程在終止時有機會去清理資源呜达,而不是武斷地將線程停止,因此這種終止線程的做法顯得更加安全和優(yōu)雅键科。

06闻丑、線程的復(fù)位

兩種復(fù)位方式:

Thread.interrupted()

通過拋出 InterruptedException 的方式

然后了解一下什么是復(fù)位:

線程運行狀態(tài)時 Thread.isInterrupted() 返回的線程狀態(tài)是 false,然后調(diào)用 thread.interrupt() 中斷線程 Thread.isInterrupted() 返回的線程狀態(tài)是 true勋颖,最后調(diào)用 Thread.interrupted() 復(fù)位線程Thread.isInterrupted() 返回的線程狀態(tài)是 false 或者拋出 InterruptedException 異常之前,線程會將狀態(tài)設(shè)為 false勋锤。

下面來看下兩種方式復(fù)位線程的代碼饭玲,首先是 Thread.interrupted() 的方式復(fù)位代碼:

public class InterruptDemo {

? ? public static void main(String[] args) throws InterruptedException {

? ? ? ? Thread thread = new Thread(() -> {

? ? ? ? ? ? while (true) {

? ? ? ? ? ? ? ? //Thread.currentThread().isInterrupted()默認(rèn)是false,當(dāng)main方式執(zhí)行thread.interrupt()時,狀態(tài)改為true

? ? ? ? ? ? ? ? if (Thread.currentThread().isInterrupted()) {

? ? ? ? ? ? ? ? ? ? System.out.println("before:" + Thread.currentThread().isInterrupted());//before:true

? ? ? ? ? ? ? ? ? ? Thread.interrupted(); // 對線程進(jìn)行復(fù)位,由 true 變成 false

? ? ? ? ? ? ? ? ? ? System.out.println("after:" + Thread.currentThread().isInterrupted());//after:false

? ? ? ? ? ? ? ? }

? ? ? ? ? ? }

? ? ? ? }, "interruptDemo");

? ? ? ? thread.start();

? ? ? ? TimeUnit.SECONDS.sleep(1);

? ? ? ? thread.interrupt();

? ? }

}

拋出 InterruptedException 復(fù)位線程代碼:

public class InterruptedExceptionDemo {

? ? public static void main(String[] args) throws InterruptedException {

? ? ? ? Thread thread = new Thread(() -> {

? ? ? ? ? ? while (!Thread.currentThread().isInterrupted()) {

? ? ? ? ? ? ? ? try {

? ? ? ? ? ? ? ? ? ? TimeUnit.SECONDS.sleep(1);

? ? ? ? ? ? ? ? } catch (InterruptedException e) {

? ? ? ? ? ? ? ? ? ? e.printStackTrace();

? ? ? ? ? ? ? ? ? ? // break;

? ? ? ? ? ? ? ? }

? ? ? ? ? ? }

? ? ? ? }, "interruptDemo");

? ? ? ? thread.start();

? ? ? ? TimeUnit.SECONDS.sleep(1);

? ? ? ? thread.interrupt();

? ? ? ? System.out.println(thread.isInterrupted());

? ? }

}

結(jié)果:

false

java.lang.InterruptedException: sleep interrupted

at java.lang.Thread.sleep(Native Method)

at java.lang.Thread.sleep(Thread.java:340)

at java.util.concurrent.TimeUnit.sleep(TimeUnit.java:386)

at com.cl.concurrentprogram.InterruptedExceptionDemo.lambda$main$0(InterruptedExceptionDemo.java:16)

at java.lang.Thread.run(Thread.java:748)

需要注意的是叁执,InterruptedException 異常的拋出并不意味著線程必須終止茄厘,而是提醒當(dāng)前線程有中斷的操作發(fā)生,至于接下來怎么處理取決于線程本身谈宛,比如

直接捕獲異常不做任何處理

將異常往外拋出

停止當(dāng)前線程次哈,并打印異常信息

像我上面的例子,如果拋出 InterruptedException 異常,我就break跳出循環(huán)讓 thread 線程終止。

為什么要復(fù)位:

Thread.interrupted() 是屬于當(dāng)前線程的吆录,是當(dāng)前線程對外界中斷信號的一個響應(yīng)窑滞,表示自己已經(jīng)得到了中斷信號,但不會立刻中斷自己恢筝,具體什么時候中斷由自己決定哀卫,讓外界知道在自身中斷前,他的中斷狀態(tài)仍然是 false撬槽,這就是復(fù)位的原因此改。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市侄柔,隨后出現(xiàn)的幾起案子共啃,更是在濱河造成了極大的恐慌,老刑警劉巖暂题,帶你破解...
    沈念sama閱讀 211,265評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件移剪,死亡現(xiàn)場離奇詭異,居然都是意外死亡敢靡,警方通過查閱死者的電腦和手機挂滓,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,078評論 2 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人赶站,你說我怎么就攤上這事幔虏。” “怎么了贝椿?”我有些...
    開封第一講書人閱讀 156,852評論 0 347
  • 文/不壞的土叔 我叫張陵想括,是天一觀的道長。 經(jīng)常有香客問我烙博,道長瑟蜈,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,408評論 1 283
  • 正文 為了忘掉前任渣窜,我火速辦了婚禮铺根,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘乔宿。我一直安慰自己位迂,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 65,445評論 5 384
  • 文/花漫 我一把揭開白布详瑞。 她就那樣靜靜地躺著掂林,像睡著了一般。 火紅的嫁衣襯著肌膚如雪坝橡。 梳的紋絲不亂的頭發(fā)上泻帮,一...
    開封第一講書人閱讀 49,772評論 1 290
  • 那天,我揣著相機與錄音计寇,去河邊找鬼锣杂。 笑死,一個胖子當(dāng)著我的面吹牛饲常,可吹牛的內(nèi)容都是我干的蹲堂。 我是一名探鬼主播,決...
    沈念sama閱讀 38,921評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼贝淤,長吁一口氣:“原來是場噩夢啊……” “哼柒竞!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起播聪,我...
    開封第一講書人閱讀 37,688評論 0 266
  • 序言:老撾萬榮一對情侶失蹤朽基,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后离陶,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體稼虎,經(jīng)...
    沈念sama閱讀 44,130評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,467評論 2 325
  • 正文 我和宋清朗相戀三年招刨,在試婚紗的時候發(fā)現(xiàn)自己被綠了霎俩。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,617評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖打却,靈堂內(nèi)的尸體忽然破棺而出杉适,到底是詐尸還是另有隱情,我是刑警寧澤柳击,帶...
    沈念sama閱讀 34,276評論 4 329
  • 正文 年R本政府宣布猿推,位于F島的核電站,受9級特大地震影響捌肴,放射性物質(zhì)發(fā)生泄漏蹬叭。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,882評論 3 312
  • 文/蒙蒙 一状知、第九天 我趴在偏房一處隱蔽的房頂上張望秽五。 院中可真熱鬧,春花似錦饥悴、人聲如沸筝蚕。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,740評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至遮斥,卻和暖如春鹊杖,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背绿映。 一陣腳步聲響...
    開封第一講書人閱讀 31,967評論 1 265
  • 我被黑心中介騙來泰國打工擒滑, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人叉弦。 一個月前我還...
    沈念sama閱讀 46,315評論 2 360
  • 正文 我出身青樓丐一,卻偏偏與公主長得像,于是被迫代替她去往敵國和親淹冰。 傳聞我的和親對象是個殘疾皇子库车,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,486評論 2 348

推薦閱讀更多精彩內(nèi)容