當一個Java程序啓動的時候,一個線程就馬上啓動,改程序一般也被咱們稱做程序的主線程。其餘全部的子線程都是由主線程產生的。主線程是程序開始就執行的,而且程序最終是以主線程的結束而結束的。java
Java編寫程序都運行在在Java虛擬機(JVM)中,在JVM的內部,程序的多任務是經過線程來實現的。每用Java命令啓動一個Java應用程序,就會啓動一個JVM進程。在同一個JVM進程中,有且只有一個進程,就是它本身。在這個JVM環境中,全部程序代碼的運行都是以線程來運行。多線程
2、多線程的概念 框架
一般,咱們接觸的簡單的程序都是單線程的,可是若是咱們須要進行「多線操做」的話,就須要藉助多線程來實現了,對於一個進程中的多個線程來講,多個線程共享進程的內存塊,當有新的線程產生的時候,操做系統不分配新的內存,而是讓新線程共享原有的進程塊的內存。所以,線程間的通訊很容易,速度也很快。不一樣的進程由於處於不一樣的內存塊,所以進程之間的通訊相對困難。this
在Java中,多線程的實現有兩種方式:繼承java.lang.Thread類;實現java.lang.Runnable接口。spa
3、繼承Thread類來實現多線程操作系統
當一個類繼承Thread類時,在類中必須重載run()方法,同時這個run()方法也是線程的入口,在調用的過程當中,經過調用start()方法來啓動新線程,其基本框架爲:線程
1 class 類名 extends Thread{ 2 方法1; 3 方法2; 4 … 5 public void run(){ 6 // other code… 7 } 8 屬性1; 9 屬性2; 10 … 11 12 }
在這裏,咱們用一個簡單的窗口買票的例子來實現此類多線程設計
1 class TestThread extends Thread 2 { 3 private String name; 4 public TestThread(String name) 5 { 6 this.name=name; 7 } 8 public void run() 9 { 10 11 for (int i = 0; i < 7; i++) 12 { 13 if (num > 0) 14 { 15 System.out.println(name+"正在賣票 "+"num= " + num--); 16 } 17 } 18 } 19 20 21 public static void main(String[] args) 22 { 23 24 TestThread h1 = new TestThread("窗口1"); 25 TestThread h2 = new TestThread("窗口2"); 26 TestThread h3 = new TestThread("窗口3"); 27 h1.start(); 28 h2.start(); 29 h3.start(); 30 } 31 32 private int num = 5; 33 }
在這個簡單的例子中,能夠很清楚的看到繼承Thread實現多線程的實現已經調用,本例中運行的結果爲:code
1 窗口1正在賣票 num= 5 2 窗口1正在賣票 num= 4 3 窗口1正在賣票 num= 3 4 窗口1正在賣票 num= 2 5 窗口1正在賣票 num= 1 6 窗口2正在賣票 num= 5 7 窗口2正在賣票 num= 4 8 窗口2正在賣票 num= 3 9 窗口2正在賣票 num= 2 10 窗口2正在賣票 num= 1 11 窗口3正在賣票 num= 5 12 窗口3正在賣票 num= 4 13 窗口3正在賣票 num= 3 14 窗口3正在賣票 num= 2 15 窗口3正在賣票 num= 1
而且這個結果有必定的不可預知性,咱們不可以肯定線程之間執行的具體順序,同時,更爲重要的,經過繼承Thread實現多線程不可以實現資源的共享,以購票爲例子,假設票的總數爲5張的話,咱們只能經過一個窗口來賣完這5張票,或者說,咱們開設了三個窗口,但這個三個窗口都有5張票,這顯然和咱們的設計理念是有點差異的。因此,實現多線程的時候,我更喜歡使用實現Runnable接口的方法。對象
4、實現Runnable接口來實現多線程
和繼承Thread相似,當一個類實現Runnable接口時,在類中也必須重載run()方法,同時這個run()方法也是線程的入口,在調用的過程當中,經過調用start()方法來啓動新線程,其基本框架爲:
1 class 類名 implements Runnable{ 2 方法1; 3 方法2; 4 … 5 public void run(){ 6 // other code… 7 } 8 屬性1; 9 屬性2; 10 … 11 12 }
在調用的時候會稍微有一些區別,仍是以簡單的窗口買票來舉例說明:
1 class MyThread implements Runnable 2 { 3 4 private int ticket = 5; //5張票 5 6 public void run() 7 { 8 for (int i=0; i<=20; i++) 9 { 10 if (this.ticket > 0) 11 { 12 System.out.println(Thread.currentThread().getName()+ "正在賣票"+this.ticket--); 13 } 14 } 15 } 16 } 17 public class TestThread { 18 19 public static void main(String [] args) 20 { 21 MyThread my = new MyThread(); 22 new Thread(my, "1號窗口").start(); 23 new Thread(my, "2號窗口").start(); 24 new Thread(my, "3號窗口").start(); 25 } 26 }
程序執行的結果爲:
1 1號窗口正在賣票5 2 1號窗口正在賣票4 3 1號窗口正在賣票3 4 2號窗口正在賣票2 5 1號窗口正在賣票1
因而,咱們看到了咱們預先設定的效果,也就是說經過實現Runnable接口的方法,咱們實現的資源的共享。
5、小結
在繼承Thread類實現多線程時,咱們建立了三個不一樣的對象,因此建立的三個線程其實是完成的三個不一樣的任務,因此纔會相互獨立的完成;而經過實現Runable接口來實現多線程時,咱們只建立了一個對象,而後實例化三個不一樣的線程去完成這個任務,因此至關因而共同完成任務。
其實,其實Thread類也是實現Runnable接口的,其源代碼以下:
1 class Thread implements Runnable { 2 //… 3 public void run() { 4 if (target != null) { 5 target.run(); 6 } 7 } 8 }
Thread中的run方法其實就是調用的是Runnable接口的run方法。方法是死的,人是活的,具體使用,能夠根據實際狀況來選擇。若是一個類繼承Thread,則不適合資源共享。可是若是實現了Runable接口的話,則突破了Java中單繼承的限制,很容易的實現資源共享。