線程基礎

一、線程的基本概念
       在操作系統中兩個比較容易混淆的概念是進程(process)和線程(thread)。操作系統中的進程是資源的組織單位。進程有一個包含了程序內容和數據的地址空間,以及其它的資源,包括打開的文件、子進程和信號處理器等。不同進程的地址空間是互相隔離的。而線程表示的是程序的執行流程,是CPU調度的基本單位。線程有自己的程序計數器、寄存器、棧和幀等。引入線程的動機在於操作系統中阻塞式I/O的存在。當一個線程所執行的I/O被阻塞的時候,同一進程中的其它線程可以使用CPU來進行計算。這樣的話,就提高了應用的執行效率。線程的概念在主流的操作系統和編程語言中都得到了支持。
       一部分的Java程序是單線程的。程序的機器指令按照程序中給定的順序依次執行。Java語言提供了java.lang.Thread類來爲線程提供抽象。有兩種方式創建一個新的線程:一種是繼承java.lang.Thread類並覆寫其中的run()方法,另外一種則是在創建java.lang.Thread類的對象的時候,在構造函數中提供一個實現了java.lang.Runnable接口的類的對象。在得到了java.lang.Thread類的對象之後,通過調用其start()方法就可以啓動這個線程的執行。
       一個線程被創建成功並啓動之後,可以處在不同的狀態中。這個線程可能正在佔用CPU時間運行;也可能處在就緒狀態,等待被調度執行;還可能阻塞在某個資源或是事件上。多個就緒狀態的線程會競爭CPU時間以獲得被執行的機會,而CPU則採用某種算法來調度線程的執行。不同線程的運行順序是不確定的,多線程程序中的邏輯不能依賴於CPU的調度算法。
  Windows操作系統是支持多線程的,它可以同時執行很多個線程,也支持多進程,因此Windows操作系統是支持多線程多進程的操作系統。Linux和Uinux也是支持多線程和多進程的操作系統。DOS就不是支持多線程和多進程了,它只支持單進程,在同一個時間點只能有一個進程在執行,這就叫單線程。
  CPU難道真的很神通廣大,能夠同時執行那麼多程序嗎?不是的,CPU的執行是這樣的:CPU的速度很快,一秒鐘可以算好幾億次,因此CPU把自己的時間分成一個個小時間片,我這個時間片執行你一會,下一個時間片執行他一會,再下一個時間片又執行其他人一會,雖然有幾十個線程,但一樣可以在很短的時間內把他們通通都執行一遍,但對我們人來說,CPU的執行速度太快了,因此看起來就像是在同時執行一樣,但實際上在一個時間點上。
  那什麼纔是真正的多線程?如果你的機器是雙CPU,或者是雙核,這確確實實是多線程。

二、線程的創建和啓動

  在JAVA裏面,JAVA的線程是通過java.lang.Thread類來實現的,每一個Thread對象代表一個新的線程。創建一個新線程出來有兩種方法:第一個是從Thread類繼承,另一個是實現接口runnable。VM啓動時會有一個由主方法(public static void main())所定義的線程,這個線程叫主線程。可以通過創建Thread的實例來創建新的線程。你只要new一個Thread對象,一個新的線程也就出現了。每個線程都是通過某個特定的Thread對象所對應的方法run()來完成其操作的,方法run()稱爲線程體。

Demo1:實現Runnable接口創建和啓動新線程
  1. package com.liangdianshui;  
  2.   
  3. public class ThreadRunable {  
  4.     public static void main(String args[]) {  
  5.         MyRunable mRunable = new MyRunable();  
  6.         // r1.run();//這個稱爲方法調用,方法調用的執行是等run()方法執行完之後纔會繼續執行main()方法  
  7.         new Thread(mRunable).start();  //啓動一個線程  
  8.         for (int i = 0; i < 10; i++) {  
  9.             System.out.println("main:" + i);  
  10.         }  
  11.     }  
  12. }  
  13.   
  14. /** 
  15.  * 自定義一個類,實現Runable接口 打印1-10 
  16.  * 
  17.  */  
  18. class MyRunable implements Runnable {  
  19.     public void run() {  
  20.         for (int i = 0; i < 10; i++) {  
  21.             System.out.println("MyRunable:" + i);  
  22.         }  
  23.     }  
  24. }  
運行結果:

 在我的機子上運行的結果是這樣,在你們的機子上運行的結果也可能不一樣的!他的運行原理是這樣的:


Demo2:繼承Thread類,重run()方法創建和啓動新的線程
[java] view plain copy 派生到我的代碼片
  1. package com.liangdianshui;  
  2.   
  3. public class ThreadExtendThread {  
  4.     public static void main(String[] args) {  
  5.         MyThread mThread = new MyThread();  
  6.         mThread.start(); // 開啓一個新的線程  
  7.         for (int i = 0; i < 10; i++) {  
  8.             System.out.println("main:" + i);  
  9.         }  
  10.     }  
  11. }  
  12.   
  13. /** 
  14.  * 繼承Thread 
  15.  * 
  16.  */  
  17. class MyThread extends Thread {  
  18.     @Override  
  19.     public void run() {  
  20.         super.run();  
  21.         for (int i = 0; i < 10; i++) {  
  22.             System.out.println("MyThread: " + i);  
  23.         }  
  24.     }  
  25. }  
  26. 使用實現Runnable接口和繼承Thread類這兩種開闢新線程的方法,在選擇上:應該優先選擇實現Runnable接口這種方式去開闢一個新的線程。因爲接口的實現可以實現多個,而類的繼承只能是單繼承。因此在開闢新線程時能夠使用Runnable接口就儘量不要使用從Thread類繼承的方式來開闢新的線程。

           通過上面的例子,我們可以這樣理解線程,主線程就是一個部門的主管,當遇到比較耗時的工作的時候,他可以安排部門的其他員工幫忙做,然後他自己繼續做下面的事情,最後只要知道員工完成的結果就行了~!

    三、線程狀態轉換
    3.1.線程控制的基本方法
    3.2. sleep/join/yield方法介紹

    Demo

    [java] view plain copy 派生到我的代碼片
    1. package com.liangdianshui;  
    2.   
    3. import java.util.Date;  
    4.   
    5. public class ThreadRunable {  
    6.     public static void main(String args[]) {  
    7.         MyRunable mRunable = new MyRunable();  
    8.         // r1.run();//這個稱爲方法調用,方法調用的執行是等run()方法執行完之後纔會繼續執行main()方法  
    9.         new Thread(mRunable).start(); // 啓動一個線程  
    10.         for (int i = 0; i < 10; i++) {  
    11.             System.out.println("main:" + i);  
    12.             if (i == 5) {  
    13.                 try {  
    14.                     System.out.println(new Date().toLocaleString());  //打印當前時間  
    15.                     Thread.sleep(5000); // 讓主線程休眠5秒  
    16.                     System.out.println(new Date().toLocaleString());  //打印當前時間  
    17.                 } catch (InterruptedException e) {  
    18.                     e.printStackTrace();  
    19.                 }  
    20.             }  
    21.         }  
    22.     }  
    23. }  
    24.   
    25. /** 
    26.  * 自定義一個類,實現Runable接口 打印1-10 
    27.  * 
    28.  */  
    29. class MyRunable implements Runnable {  
    30.     public void run() {  
    31.         for (int i = 0; i < 10; i++) {  
    32.             System.out.println("MyRunable:" + i);  
    33.         }  
    34.     }  
    35. }  

    運行結果:

    Demo:

    [java] view plain copy 派生到我的代碼片
    1. package com.liangdianshui;  
    2.   
    3. import java.util.Date;  
    4.   
    5. public class ThreadRunable {  
    6.     public static void main(String args[]) {  
    7.         MyRunable mRunable = new MyRunable();  
    8.         // r1.run();//這個稱爲方法調用,方法調用的執行是等run()方法執行完之後纔會繼續執行main()方法  
    9.         Thread mThread = new Thread(mRunable);  
    10.         mThread.start(); // 啓動一個線程  
    11.         for (int i = 0; i < 10; i++) {  
    12.             System.out.println("main:" + i);  
    13.         }  
    14.         try {  
    15.             mThread.join();  //把子線程合併到主線程,等於是調用子線程的方法  
    16.         } catch (InterruptedException e) {  
    17.             e.printStackTrace();  
    18.         }  
    19.     }  
    20. }  
    21.   
    22. /** 
    23.  * 自定義一個類,實現Runable接口 打印1-10 
    24.  * 
    25.  */  
    26. class MyRunable implements Runnable {  
    27.     public void run() {  
    28.         for (int i = 0; i < 10; i++) {  
    29.             System.out.println("MyRunable:" + i);  
    30.             if (i == 2) {  
    31.                 try {  
    32.                     Thread.sleep(2000);  
    33.                 } catch (InterruptedException e) {  
    34.                     // TODO Auto-generated catch block  
    35.                     e.printStackTrace();  
    36.                 }  
    37.             }  
    38.         }  
    39.     }  
    40. }  

    運行結果:

     join方法你可以理解爲是直接停止了那個子線程,然後在主線程中繼續運行!

    Demo:
    [java] view plain copy 派生到我的代碼片
    1. package com.liangdianshui;  
    2.   
    3. import java.util.Date;  
    4.   
    5. public class ThreadRunable {  
    6.     public static void main(String args[]) {  
    7.         MyThread1 t1 = new MyThread1("t1");  
    8.         MyThread1 t2 = new MyThread1("t2");  
    9.         t1.start();  
    10.         t2.start();  
    11.     }  
    12. }  
    13.   
    14. class MyThread1 extends Thread {  
    15.   
    16.     private String strName;  
    17.   
    18.     public MyThread1(String str) {  
    19.         strName = str;  
    20.     }  
    21.   
    22.     public void run() {  
    23.         for (int i = 0; i < 10; i++) {  
    24.             System.out.println(strName + ":" + i);  
    25.             try {  
    26.                 Thread.sleep(1000); //爲了更好的顯示效果,增加延遲  
    27.             } catch (InterruptedException e) {  
    28.                 // TODO Auto-generated catch block  
    29.                 e.printStackTrace();  
    30.             }  
    31.             if (i % 2 == 0) {  
    32.                 yield();  
    33.             }  
    34.         }  
    35.     }  
    36.   
    37. }  
    四、線程的優先級別

    五、線程同步


    六、總結
            這篇博文首先簡單的介紹了什麼是進程和線程,知道單個CPU不是真正意義上的多進程,CPU把自己的時間分成一個個小時間片,我這個時間片執行你一會,下一個時間片執行他一會,加上CPU的運行速度很快,因此像同時運行多個程序一樣,然後瞭解實現Thread的兩種方法,一種是實現Runable接口,一種是繼承Thread類,最後講了線程的一些方法!
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章