日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

线程最最基础的知识

發(fā)布時(shí)間:2024/8/23 编程问答 49 豆豆
生活随笔 收集整理的這篇文章主要介紹了 线程最最基础的知识 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.


什么是線程

試想一下沒有線程的程序是怎么樣的?百度網(wǎng)盤在上傳文件時(shí)就無法下載文件了,得等文件上傳完成后才能下載文件。這個(gè)我們現(xiàn)在看起來很反人性,因?yàn)槲覀兞?xí)慣了一個(gè)程序同時(shí)可以進(jìn)行運(yùn)行多個(gè)功能,而這些都是線程的功勞。

之前的文章?進(jìn)程知多少?中講到,為了實(shí)現(xiàn)多個(gè)程序并行執(zhí)行,引入了進(jìn)程概念。現(xiàn)在引入線程是為了讓一個(gè)程序能夠并發(fā)執(zhí)行。

線程的組成

線程ID:線程標(biāo)識符。

當(dāng)前指令指針(PC):指向要執(zhí)行的指令。

寄存器集合:存儲單元寄存器的集合。

堆棧:暫時(shí)存放數(shù)據(jù)和地址,一般用來保護(hù)斷點(diǎn)和現(xiàn)場。

線程與進(jìn)程區(qū)別

線程和進(jìn)程之間的區(qū)別,我覺得可以用這個(gè)例子來看出兩者的不同,進(jìn)程就是一棟房子,房子住著 3 個(gè)人,線程就是住在房子里的人。進(jìn)程是一個(gè)獨(dú)立的個(gè)體,有自己的資源,線程是在進(jìn)程里的,多個(gè)線程共享著進(jìn)程的資源。

線程狀態(tài)

我們看到 Java 源代碼里面,線程狀態(tài)的枚舉有如下 6 個(gè)。

public enum State {//新建狀態(tài) NEW,//運(yùn)行狀態(tài) RUNNABLE,//阻塞狀態(tài) BLOCKED,//等待狀態(tài) WAITING,//等待狀態(tài)(區(qū)別在于這個(gè)有等待的時(shí)間) TIMED_WAITING,//終止?fàn)顟B(tài) TERMINATED;}

下面給這 6 個(gè)狀態(tài)一一做下解釋。

  • NEW:新建狀態(tài)。在創(chuàng)建完 Thread ,還沒執(zhí)行 start() 之前,線程的狀態(tài)一直是 NEW。可以說這個(gè)時(shí)候還沒有真正的一個(gè)線程映射著,只是一個(gè)對象。

  • RUNNABLE:運(yùn)行狀態(tài)。線程對象調(diào)用 start() 之后,就進(jìn)入 RUNNABLE 狀態(tài),該狀態(tài)說明在 JVM 中有一個(gè)真實(shí)的線程存在。

  • BLOCKED:阻塞狀態(tài)。線程在等待鎖的釋放,也就是等待獲取 monitor 鎖。

  • WAITING:等待狀態(tài)。線程在這個(gè)狀態(tài)的時(shí)候,不會(huì)被分配 CPU,而且需要被顯示地喚醒,否則會(huì)一直等待下去。

  • TIMED_WAITING:超時(shí)等待狀態(tài)。這個(gè)狀態(tài)的線程也一樣不會(huì)被分配 CPU,但是它不會(huì)無限等待下去,有時(shí)間限制,時(shí)間一到就停止等待。

  • TERMINATED:終止?fàn)顟B(tài)。線程執(zhí)行完成結(jié)束,但不代表這個(gè)對象已經(jīng)沒有了,對象可能還是存在的,只是線程不存在了。

線程既然有這么多個(gè)狀態(tài),那肯定就有狀態(tài)機(jī),也就是在什么情況下 A 狀態(tài)會(huì)變成 B 狀態(tài)。下面就來簡單描述一下。

結(jié)合下圖,我們 new 出線程類的時(shí)候,就是 NEW 狀態(tài),調(diào)用 start()?方法,就進(jìn)入了 RUNNABLE 狀態(tài),這時(shí)如果觸發(fā)等待,則進(jìn)入了 WAITING 狀態(tài),如果觸發(fā)超時(shí)等待,則進(jìn)入 TIMED_WAITING 狀態(tài),當(dāng)訪問需要同步的資源時(shí),則只有一個(gè)線程能訪問,其他線程就進(jìn)入 BLOCKED 狀態(tài),當(dāng)線程執(zhí)行完后,進(jìn)入 TERMINATED 狀態(tài)。

圖片來源于網(wǎng)路,侵刪

其實(shí)在 JVM 中,線程是有 9 個(gè)狀態(tài),如下所示,有興趣的同學(xué)可以深入了解一下。

javaClasses.hppenum ThreadStatus { NEW = 0, RUNNABLE = JVMTI_THREAD_STATE_ALIVE + // runnable / running JVMTI_THREAD_STATE_RUNNABLE, SLEEPING = JVMTI_THREAD_STATE_ALIVE + // Thread.sleep() JVMTI_THREAD_STATE_WAITING + JVMTI_THREAD_STATE_WAITING_WITH_TIMEOUT + JVMTI_THREAD_STATE_SLEEPING, IN_OBJECT_WAIT = JVMTI_THREAD_STATE_ALIVE + // Object.wait() JVMTI_THREAD_STATE_WAITING + JVMTI_THREAD_STATE_WAITING_INDEFINITELY + JVMTI_THREAD_STATE_IN_OBJECT_WAIT, IN_OBJECT_WAIT_TIMED = JVMTI_THREAD_STATE_ALIVE + // Object.wait(long) JVMTI_THREAD_STATE_WAITING + JVMTI_THREAD_STATE_WAITING_WITH_TIMEOUT + JVMTI_THREAD_STATE_IN_OBJECT_WAIT, PARKED = JVMTI_THREAD_STATE_ALIVE + // LockSupport.park() JVMTI_THREAD_STATE_WAITING + JVMTI_THREAD_STATE_WAITING_INDEFINITELY + JVMTI_THREAD_STATE_PARKED, PARKED_TIMED = JVMTI_THREAD_STATE_ALIVE + // LockSupport.park(long) JVMTI_THREAD_STATE_WAITING + JVMTI_THREAD_STATE_WAITING_WITH_TIMEOUT + JVMTI_THREAD_STATE_PARKED, BLOCKED_ON_MONITOR_ENTER = JVMTI_THREAD_STATE_ALIVE + // (re-)entering a synchronization block JVMTI_THREAD_STATE_BLOCKED_ON_MONITOR_ENTER, TERMINATED = JVMTI_THREAD_STATE_TERMINATED};

Java 線程實(shí)現(xiàn)

下面講一講在 Java 中如何創(chuàng)建一個(gè)線程。眾所周知,實(shí)現(xiàn) Java 線程有 2 種方式:繼承 Thread 類和實(shí)現(xiàn) Runnable 接口。

繼承 Thread 類

繼承 Thread 類,重寫 run()?方法。

class MyThread extends Thread {@Override public void run() { System.out.println("MyThread"); } }

實(shí)現(xiàn) Runnable 接口

實(shí)現(xiàn) Runnable 接口,實(shí)現(xiàn) run()?方法。

class MyRunnable implements Runnable {public void run() { System.out.println("MyRunnable"); } }

這 2 種線程的啟動(dòng)方式也不一樣。MyThread 是一個(gè)線程類,所以可以直接 new 出一個(gè)對象出來,接著調(diào)用 start()?方法來啟動(dòng)線程;而 MyRunnable 只是一個(gè)普通的類,需要 new 出線程基類 Thread 對象,將 MyRunnable 對象傳進(jìn)去。

下面是啟動(dòng)線程的方式:

public class ThreadImpl {public static void main(String[] args) { MyThread myThread = new MyThread(); Thread myRunnable = new Thread(new MyRunnable()); System.out.println("main Thread begin"); myThread.start(); myRunnable.start(); System.out.println("main Thread end"); } }

打印結(jié)果如下:

main Thread beginmain Thread endMyThreadMyRunnable

看這結(jié)果,不像咱們之前的串行執(zhí)行依次打印,主線程不會(huì)等待子線程執(zhí)行完。

敲重點(diǎn):不能直接調(diào)用 run(),直接調(diào)用 run()?不會(huì)創(chuàng)建線程,而是主線程直接執(zhí)行 run()?的內(nèi)容,相當(dāng)于執(zhí)行普通函數(shù)。這時(shí)就是串行執(zhí)行的。看下面代碼:

public class ThreadImpl {public static void main(String[] args) { MyThread myThread = new MyThread(); Thread myRunnable = new Thread(new MyRunnable()); System.out.println("main Thread begin"); myThread.run(); myRunnable.run(); System.out.println("main Thread end"); } }

打印結(jié)果:

main Thread beginMyThreadMyRunnablemain?Thread?end 從結(jié)果看出只是串行的,但看不出沒有線程,我們看下面例子來驗(yàn)證直接調(diào)用 run() 方法沒有創(chuàng)建新的線程,使用 VisualVM 工具來觀察線程情況。我們對代碼做一下 修改,加上 Thread.sleep(1000000) 讓它睡眠一段時(shí)間,這樣方便用工具查看線程情況。

調(diào)用 run()?的代碼:

public class ThreadImpl {public static void main(String[] args) { MyThread myThread = new MyThread(); myThread.setName("MyThread"); Thread myRunnable = new Thread(new MyRunnable()); myRunnable.setName("MyRunnable"); System.out.println("main Thread begin"); myThread.run(); myRunnable.run(); System.out.println("main Thread end"); try { Thread.sleep(1000000); } catch (InterruptedException e) { e.printStackTrace(); } } }class MyThread extends Thread {@Override public void run() { System.out.println("MyThread"); try { Thread.sleep(1000000); } catch (InterruptedException e) { e.printStackTrace(); } } }class MyRunnable implements Runnable {public void run() { System.out.println("MyRunnable"); try { Thread.sleep(1000000); } catch (InterruptedException e) { e.printStackTrace(); } } }

運(yùn)行結(jié)果:

main Thread beginMyThread

只打印出 2 句日志,觀察線程時(shí)也只看到 main 線程,沒有看到 MyThread 和 MyRunnable 線程,印證了上面咱們說的:直接調(diào)用 run()?方法,沒有創(chuàng)建線程。

下面我們來看看有調(diào)用 start()?的代碼:

public class ThreadImpl {public static void main(String[] args) { MyThread myThread = new MyThread(); myThread.setName("MyThread"); Thread myRunnable = new Thread(new MyRunnable()); myRunnable.setName("MyRunnable"); System.out.println("main Thread begin"); myThread.start(); myRunnable.start(); System.out.println("main Thread end"); try { Thread.sleep(1000000); } catch (InterruptedException e) { e.printStackTrace(); } } }

運(yùn)行結(jié)果:

main Thread beginmain Thread endMyThreadMyRunnable

所有日志都打印出來了,并且通過 VisualVM 工具可以看到 MyThread 和 MyRunnable 線程。看到了這個(gè)結(jié)果,切記創(chuàng)建線程要調(diào)用 start()?方法。

————

編輯?∑Gemini

?來源:CSDN云計(jì)算

?92年的小哥,985的特聘教授:3年博士期間發(fā)表40篇SCI

?數(shù)學(xué)家家譜之可視化

?曾撿破爛為生,窮到?jīng)]飯吃,現(xiàn)在身家395億,給員工發(fā)3億年終獎(jiǎng)!

?“四院院士”新任北大理學(xué)部主任,這位頂尖科學(xué)家有多牛?

?假如有人把支付寶存儲服務(wù)器炸了(物理炸),大眾在支付寶里的錢是不是就都沒有了呢?

?又一位!發(fā)40篇SCI,90后博士受聘985教授

算法數(shù)學(xué)之美微信公眾號歡迎賜稿

稿件涉及數(shù)學(xué)、物理、算法、計(jì)算機(jī)、編程等相關(guān)領(lǐng)域,經(jīng)采用我們將奉上稿酬。

投稿郵箱:math_alg@163.com

總結(jié)

以上是生活随笔為你收集整理的线程最最基础的知识的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。