java 中兩種多線程的區別,start方法和run方法的啓動區別

直接上代碼看的更清晰:html

package org.thread.demo;  
public class MyThread extends Thread{  
        private String name;  
        public MyThread(String name) {  
            super();  
            this.name = name;  
        }  
        public void run(){  
        for(int i=0;i<10;i++){ 
             System.out.println("線程開始:"+this.name+",i="+i);  
        } 
    }  
}  

package org.thread.demo;  
public class ThreadDemo01 {  
        public static void main(String[] args) {  
        MyThread mt1=new MyThread("線程a");  
        MyThread mt2=new MyThread("線程b");  
        mt1.run();  
        mt2.run();  
    }  
}

  運行發現結果頗有規律,先第一個對象執行,而後第二個對象執行,並無相互運行。在JDK的文檔中能夠發現,一旦調用start方法,則會經過JVM找到run方法。下面啓動start方法啓動線程:java

package org.thread.demo;  
public class ThreadDemo01 {  
        public static void main(String[] args) {  
        MyThread mt1=new MyThread("線程a");  
        MyThread mt2=new MyThread("線程b");  
        mt1.start();  
        mt2.start();  
    }  
}

這樣程序能夠正常完成交互式運行。那麼爲啥非要使用start方法啓動多線程呢?多線程

在JDK的安裝路徑下,src.zip是所有的java源程序,經過此代碼找到Thread中的start方法的定義,能夠發現此方法中使用了private native void start0();其中native關鍵字表示能夠調用操做系統的底層函數,那麼這樣的技術稱爲JNI技術(java Native Interface)ide

Runnable接口函數

在實際開發中一個多線程的操做不多使用Thread類,而是經過Runnable接口完成。this

package org.runnable.demo;  
public class MyThread implements Runnable{  
    private String name;  
    public MyThread(String name) {  
        this.name = name;  
    }
    public void run(){  
        for(int i=0;i<100;i++){  
            System.out.println("線程開始:"+this.name+",i="+i);  
        }  
    }  
}

      可是在使用Runnable定義的子類中沒有start方法,只有Thread類中才有。此時觀察Thread類,有一個構造方法:public Thread(Runnable targer) 此構造方法接受Runnable的子類實例,也就是說能夠經過Thread類來啓動Runnable實現的多線程。(start方法能夠協調系統的資源):spa

package org.runnable.demo;  
import org.runnable.demo.MyThread;  
public class ThreadDemo01 {  
    public static void main(String[] args) {  
        MyThread mt1=new MyThread("線程a");  
        MyThread mt2=new MyThread("線程b");  
        new Thread(mt1).start();  
        new Thread(mt2).start();  
    }  
}

 

兩種實現方式的區別和聯繫:操作系統

在程序開發中只要是多線程確定永遠以實現Runnable接口爲主,由於實現Runnable接口相比繼承Thread類有以下好處:線程

  • 避免點繼承的侷限,一個類能夠實現多個接口。code

  • 適合於資源的共享

以賣電影券程序爲例,經過Thread類完成:

package org.demo.dff;  
public class MyThread extends Thread{  
    private int ticket=10;  
    public void run(){  
        for(int i=0;i<20;i++){  
            if(this.ticket>0){  
                System.out.println("賣電影券:ticket"+this.ticket--);  
            }  
        }  
    }  
}

下面經過三個線程對象,同時賣電影券:

package org.demo.dff;  
public class ThreadTicket {  
    public static void main(String[] args) {  
        MyThread mt1=new MyThread();  
        MyThread mt2=new MyThread();  
        MyThread mt3=new MyThread();  
        mt1.start();//每一個線程都各賣了10張,共賣了30張電影券  
        mt2.start();//但實際只有10張電影券,每一個線程都賣本身的電影券  
        mt3.start();//沒有達到資源共享  
    }  
}

若是用Runnable就能夠實現資源共享,下面看例子:

package org.demo.runnable;  
public class MyThread implements Runnable{  
    private int ticket=10;  
    public void run(){  
        for(int i=0;i<20;i++){  
            if(this.ticket>0){  
                System.out.println("賣電影券:ticket"+this.ticket--);  
            }  
        }  
    }  
}  
package org.demo.runnable;  
public class RunnableTicket {  
    public static void main(String[] args) {  
        MyThread mt=new MyThread();  
        new Thread(mt).start();//同一個mt,可是在Thread中就不能夠,若是用同一個實例化對象mt,就會出現異常  
        new Thread(mt).start();new Thread(mt).start();  
    }  
}

 

雖然如今程序中有三個線程,可是一共賣了10張電影券,也就是說使用Runnable實現多線程能夠達到資源共享目的。

Runnable接口和Thread之間的聯繫:

public class Thread extends Object implements Runnable

發現Thread類也是Runnable接口的子類。

 

Java線程中run和start方法的區別

    Thread類中run()和start()方法的區別以下:
        run()方法: 在本線程內調用該Runnable對象的run()方法,能夠重複屢次調用;
        start()方法: 啓動一個線程,調用該Runnable對象的run()方法,不能屢次啓動一個線程;

package com.ljq.test;

public class ThreadTest {
    
    /**
     * 觀察直接調用run()和用start()啓動一個線程的差異 
     * 
     * @param args
     * @throws Exception
     */
    public static void main(String[] args){
        Thread thread=new ThreadDemo();
        //第一種
        //代表: run()和其餘方法的調用沒任何不一樣,main方法按順序執行了它,並打印出最後一句
        //thread.run();
        
        //第二種
        //代表: start()方法從新建立了一個線程,在main方法執行結束後,因爲start()方法建立的線程沒有運行結束,
        //所以主線程未能退出,直到線程thread也執行完畢.這裏要注意,默認建立的線程是用戶線程(非守護線程)
        //thread.start();
        
        //第三種
        //一、爲何沒有打印出100句呢?由於咱們將thread線程設置爲了daemon(守護)線程,程序中只有守護線程存在的時候,是能夠退出的,因此只打印了七句便退出了
        //二、當java虛擬機中有守護線程在運行的時候,java虛擬機會關閉。當全部常規線程運行完畢之後,
        //守護線程無論運行到哪裏,虛擬機都會退出運行。因此你的守護線程最好不要寫一些會影響程序的業務邏輯。不然沒法預料程序到底會出現什麼問題
        //thread.setDaemon(true);
        //thread.start();
        
        //第四種
        //用戶線程能夠被System.exit(0)強制kill掉,因此也只打印出七句
        thread.start();
        System.out.println("main thread is over");
        System.exit(1);
    }
    
    public static class ThreadDemo extends Thread{
        @Override
        public void run() {
            for (int i = 0; i < 100; i++) {
                System.out.println("This is a Thread test"+i);
            }
        }
    }
}

放大招(哈哈),總結:

1) start:

        用start方法來啓動線程,真正實現了多線程運行,這時無需等待run方法體代碼執行完畢而直接繼續執行下面的代碼。經過調用Thread類的start()方法來啓動一個線程,這時此線程處於就緒(可運行)狀態,並無運行,一旦獲得cpu時間片,就開始執行run()方法,這裏方法run()稱爲線程體,它包含了要執行的這個線程的內容,Run方法運行結束,此線程隨即終止。

2) run:

        run()方法只是類的一個普通方法而已,若是直接調用Run方法,程序中依然只有主線程這一個線程,其程序執行路徑仍是隻有一條,仍是要順序執行,仍是要等待run方法體執行完畢後纔可繼續執行下面的代碼,這樣就沒有達到多線程的目的。

總結:調用start方法方可啓動線程,而run方法只是thread的一個普通方法調用,仍是在主線程裏執行

相關文章
相關標籤/搜索