目錄
三 、通過 Thread 類 和 Runnable 接口實現多線程的區別
一 、進程 與 線程
進程是程序的一次動態的執行過程。多進程系統可以同時運行多個進程(也就是程序),而線程是比進程更小的執行單位,比如運行一個聽歌的軟件(進程),播放歌曲就是其中一個線程,搜索歌曲也是一個線程,瀏覽評論也是一個線程
多線程是指一個進程在執行過程中可以產生多個線程,這些線程可以同時存在,同時運行,所以一個進程可能包含了多個同時執行的線程。
多線程是實現併發機制的一種有效手段
二 、Java中多線程的實現
在Java中要想實現多線程代碼有兩種方法:
【1】繼承 Thread 類
【2】實現 Runnable 接口
1 、繼承 Thread 類實現多線程
Thread 類是在Java.lang包中定義,一個類如果繼承了 Thread 類,此類就稱爲多線程操作類,在Thread子類中,必須明確地覆寫 run() 方法,並通過 start() 方法啓動線程
class MyThread extends Thread{ //繼承Thread類
private String name;
public MyThread(String name){
this.name = name;
}
public void run(){ //覆寫Thread類中的run()方法
for (int i=0; i<10; i++){
System.out.println(name + "運行,i = " + i);
}
}
}
public class ThreadDemo01 {
public static void main(String[] args) {
MyThread mt1 = new MyThread("線程A");
MyThread mt2 = new MyThread("線程B");
mt1.start(); //調用start()方法啓動線程
mt2.start(); //調用start()方法啓動線程
}
}
程序運行結果(可能的一種結果):
從程序的運行結果可以發現,兩個線程交替運行,哪個線程對象搶到了CPU資源,哪個線程就可以運行,所以程序每次的運行結果都不一樣
提問:爲什麼啓動線程必須通過start()方法啓動,而不能直接調用 run() 方法呢?
回答:由於多線程的實現需要依靠底層操作系統得支持,start() 方法除了會調用run() 方法,還有一些調用本機操作系統的函數。另外,一個線程對象只能調用一次start()方法,調用一次便可以啓動多線程,如果調用多次,則會拋出異常
繼承 Thread 類可以實現多線程,但會受到單繼承侷限的影響,所以,還可以通過實現Runnable接口實現多線程
2 、實現 Runnable 接口實現多線程
查閱JDK文檔發現,Runnable 接口只定義了一個 run() 方法
要想啓動一個多線程必須使用 start() 方法完成,那麼此時該如何啓動多線程呢?
查閱JDK文檔的Thread類發現其有構造方法可以接收Runnable的子類實例對象,所以就可以依靠此點啓動多線程
實現Runnable接口,通過Thread類啓動多線程
class MyThread implements Runnable{ //實現Runnable接口
private String name;
public MyThread(String name){
this.name = name;
}
public void run(){ //覆寫Runnable接口中的run()方法
for (int i=0; i<10; i++){
System.out.println(name + "運行,i = " + i);
}
}
}
public class RunnableDemo01 {
public static void main(String[] args) {
MyThread mt1 = new MyThread("線程C"); //實例化Runnable子類對象
MyThread mt2 = new MyThread("線程D"); //實例化Runnable子類對象
Thread t1 = new Thread(mt1); //實例化Thread類對象
Thread t2 = new Thread(mt2); //實例化Thread類對象
t1.start(); //啓動線程
t2.start(); //啓動線程
}
}
程序運行結果(可能的一種結果):
三 、通過 Thread 類 和 Runnable 接口實現多線程的區別
使用 Thread 類實現多線程時無法實現資源共享,而實現 Runnable 接口實現多線程可以實現資源共享
1 、繼承 Thread 類不能資源共享
class MyThread extends Thread{
private int ticket = 5; //一共有5張票
public void run(){
for (int i=0; i<100; i++){
if (ticket>0){ //判斷是否有餘票
System.out.println("賣票:ticket = " + ticket--);
}
}
}
}
public class ThreadDemo02 {
public static void main(String[] args) {
MyThread mt1 = new MyThread();
MyThread mt2 = new MyThread();
MyThread mt3 = new MyThread();
mt1.start();
mt2.start();
mt3.start();
}
}
程序運行結果:
從程序的運行結果可以發現,每個線程都各自賣自己的5張票,沒有達到資源共享
2 、實現 Runnable 接口實現資源共享
class MyThread implements Runnable{
private int ticket = 5; //一共5張票
public void run(){
for (int i=0; i<100; i++){
if (ticket>0){ //判斷是否有餘票
System.out.println("賣票:ticket = " + ticket--);
}
}
}
}
public class RunnableDemo02 {
public static void main(String[] args) {
MyThread mt = new MyThread();
//啓動3個線程
new Thread(mt).start();
new Thread(mt).start();
new Thread(mt).start();
}
}
程序運行結果:
3個線程一共賣了5張票
實現 Runnable 接口相對於繼承 Thread類來說,有如下優勢:
【1】適合多個相同程序代碼的線程去處理同一資源的情況
【2】可以避免由於Java的單繼承特性帶來的侷限
【3】增強了程序的健壯性,代碼能夠被多個線程共享,代碼與數據是獨立的
所以在開發中建議使用 Runnable 接口實現多線程