乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      線程最最基礎(chǔ)的知識(shí)

       web3佬總圖書館 2019-09-25

      在這里插入圖片描述

      Java 多線程系列文章第 5 篇。

      什么是線程

      試想一下沒(méi)有線程的程序是怎么樣的?百度網(wǎng)盤在上傳文件時(shí)就無(wú)法下載文件了,得等文件上傳完成后才能下載文件。這個(gè)我們現(xiàn)在看起來(lái)很反人性,因?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)識(shí)符。

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

      寄存器集合:存儲(chǔ)單元寄存器的集合。

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

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

      線程和進(jìn)程之間的區(qū)別,我覺(jué)得可以用這個(gè)例子來(lái)看出兩者的不同,進(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;}
      • 1

      • 2

      • 3

      • 4

      • 5

      • 6

      • 7

      • 8

      • 9

      • 10

      • 11

      • 12

      • 13

      • 14

      • 15

      • 16

      • 17

      • 18

      • 19

      • 20

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

      NEW:新建狀態(tài)。在創(chuàng)建完 Thread ,還沒(méi)執(zhí)行 start() 之前,線程的狀態(tài)一直是 NEW??梢哉f(shuō)這個(gè)時(shí)候還沒(méi)有真正的一個(gè)線程映射著,只是一個(gè)對(duì)象。

      RUNNABLE:運(yùn)行狀態(tài)。線程對(duì)象調(diào)用 start() 之后,就進(jìn)入 RUNNABLE 狀態(tài),該狀態(tài)說(shuō)明在 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ì)無(wú)限等待下去,有時(shí)間限制,時(shí)間一到就停止等待。

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

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

      結(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)訪問(wèn)需要同步的資源時(shí),則只有一個(gè)線程能訪問(wèn),其他線程就進(jìn)入 BLOCKED 狀態(tài),當(dāng)線程執(zhí)行完后,進(jìn)入 TERMINATED 狀態(tài)。
      在這里插入圖片描述
      其實(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};
      • 1

      • 2

      • 3

      • 4

      • 5

      • 6

      • 7

      • 8

      • 9

      • 10

      • 11

      • 12

      • 13

      • 14

      • 15

      • 16

      • 17

      • 18

      • 19

      • 20

      • 21

      • 22

      • 23

      • 24

      • 25

      • 26

      • 27

      • 28

      • 29

      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'); }}
      • 1

      • 2

      • 3

      • 4

      • 5

      • 6

      • 7

      • 8

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

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

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

      • 2

      • 3

      • 4

      • 5

      • 6

      • 7

      這 2 種線程的啟動(dòng)方式也不一樣。MyThread 是一個(gè)線程類,所以可以直接 new 出一個(gè)對(duì)象出來(lái),接著調(diào)用 start() 方法來(lái)啟動(dòng)線程;而 MyRunnable 只是一個(gè)普通的類,需要 new 出線程基類 Thread 對(duì)象,將 MyRunnable 對(duì)象傳進(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'); }}
      • 1

      • 2

      • 3

      • 4

      • 5

      • 6

      • 7

      • 8

      • 9

      • 10

      • 11

      • 12

      打印結(jié)果如下:

      main Thread beginmain Thread endMyThreadMyRunnable
      • 1

      • 2

      • 3

      • 4

      看這結(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í)行的??聪旅娲a。

      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'); }}
      • 1

      • 2

      • 3

      • 4

      • 5

      • 6

      • 7

      • 8

      • 9

      • 10

      • 11

      • 12

      打印結(jié)果:

      main Thread beginMyThreadMyRunnablemain Thread end
      • 1

      • 2

      • 3

      • 4

      從結(jié)果看出只是串行的,但看不出沒(méi)有線程,我們看下面例子來(lái)驗(yàn)證直接調(diào)用 run() 方法沒(méi)有創(chuàng)建新的線程,使用 VisualVM 工具來(lái)觀察線程情況。

      我們對(duì)代碼做一下修改,加上 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(); } }}
      • 1

      • 2

      • 3

      • 4

      • 5

      • 6

      • 7

      • 8

      • 9

      • 10

      • 11

      • 12

      • 13

      • 14

      • 15

      • 16

      • 17

      • 18

      • 19

      • 20

      • 21

      • 22

      • 23

      • 24

      • 25

      • 26

      • 27

      • 28

      • 29

      • 30

      • 31

      • 32

      • 33

      • 34

      • 35

      • 36

      • 37

      • 38

      • 39

      • 40

      • 41

      • 42

      • 43

      • 44

      • 45

      • 46

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

      main Thread beginMyThread
      • 1

      • 2

      在這里插入圖片描述
      只打印出 2 句日志,觀察線程時(shí)也只看到 main 線程,沒(méi)有看到 MyThreadMyRunnable 線程,印證了上面咱們說(shuō)的:直接調(diào)用 run() 方法,沒(méi)有創(chuàng)建線程。

      下面我們來(lái)看看有
      調(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(); } } }
      • 1

      • 2

      • 3

      • 4

      • 5

      • 6

      • 7

      • 8

      • 9

      • 10

      • 11

      • 12

      • 13

      • 14

      • 15

      • 16

      • 17

      • 18

      • 19

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

      main Thread beginmain Thread endMyThreadMyRunnable
      • 1

      • 2

      • 3

      • 4

      在這里插入圖片描述
      所有日志都打印出來(lái)了,并且通過(guò) VisualVM 工具可以看到 MyThreadMyRunnable 線程。看到了這個(gè)結(jié)果,切記創(chuàng)建線程要調(diào)用 start() 方法。

      今天就先講到這,繼續(xù)關(guān)注后面的內(nèi)容。

        本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
        轉(zhuǎn)藏 分享 獻(xiàn)花(0

        0條評(píng)論

        發(fā)表

        請(qǐng)遵守用戶 評(píng)論公約

        類似文章 更多