Java多線程學習1——兩種基本實現框架
一、前言
當一個Java程序啟動的時候,一個線程就立刻啟動,改程序通常也被我們稱作程序的主線程。其他所有的子線程都是由主線程產生的。主線程是程序開始就執行的,並且程序最終是以主線程的結束而結束的。
Java編寫程序都運行在在Java虛擬機(JVM)中,在JVM的內部,程序的多任務是通過線程來實現的。每用Java命令啟動一個Java應用程序,就會啟動一個JVM進程。在同一個JVM進程中,有且只有一個進程,就是它自己。在這個JVM環境中,所有程序代碼的運行都是以線程來運行。
二、多線程的概念
通常,我們接觸的簡單的程序都是單線程的,但是如果我們需要進行“多線操作”的話,就需要借助多線程來實現了,對於一個進程中的多個線程來說,多個線程共享進程的內存塊,當有新的線程產生的時候,操作系統不分配新的內存,而是讓新線程共享原有的進程塊的內存。因此,線程間的通信很容易,速度也很快。不同的進程因為處於不同的內存塊,因此進程之間的通信相對困難。
在Java中,多線程的實現有兩種方式:繼承java.lang.Thread類;實現java.lang.Runnable接口。
三、繼承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實現多線程的實現已經調用,本例中運行的結果為:
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接口的方法。
四、實現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接口的方法,我們實現的資源的共享。
五、小結
在繼承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中單繼承的限制,很容易的實現資源共享。
多線程是Java中非常重要的部分,本文只涉及到多線程最基本的實現以及調用的部分,例如兩個例子運行可能涉及到同步的問題,運行結果可能會有所出入,今后會陸續更新一些深入的東西,希望能對后來的學習者有所幫助。
Reference:http://www.cnblogs.com/rollenholt/archive/2011/08/28/2156357.html