一、能夠避免因爲Java的單繼承特性而帶來的侷限;sql
二、加強程序的健壯性,代碼可以被多個線程共享,代碼與數據是獨立的;安全
三、適合多個相同程序代碼的線程區處理同一資源的狀況。多線程
下面以典型的買票程序(基本都是以這個爲例子)爲例,來講明兩者的區別。架構
首先經過繼承Thread類實現,代碼以下:併發
class MyThread extends Thread{ private int ticket = 5; public void run(){ for (int i=0;i<10;i++) { if(ticket > 0){ System.out.println("ticket = " + ticket--); } } } } public class ThreadDemo{ public static void main(String[] args){ new MyThread().start(); new MyThread().start(); new MyThread().start(); } }
某次的執行結果以下:分佈式
從結果中能夠看出,每一個線程單獨賣了5張票,即獨立地完成了買票的任務,但實際應用中,好比火車站售票,須要多個線程去共同完成任務,在本例中,即多個線程共同買5張票。高併發
下面是經過實現Runnable接口實現的多線程程序,代碼以下:性能
class MyThread implements Runnable{ private int ticket = 5; public void run(){ for (int i=0;i<10;i++) { if(ticket > 0){ System.out.println("ticket = " + ticket--); } } } } public class RunnableDemo{ public static void main(String[] args){ MyThread my = new MyThread(); new Thread(my).start(); new Thread(my).start(); new Thread(my).start(); } }
某次的執行結果以下:學習
從結果中能夠看出,三個線程一共賣了5張票,即它們共同完成了買票的任務,實現了資源的共享。spa
針對以上代碼補充三點:
一、在第二種方法(Runnable)中,ticket輸出的順序並非54321,這是由於線程執行的時機難以預測,ticket–並非原子操做。
二、在第一種方法中,咱們new了3個Thread對象,即三個線程分別執行三個對象中的代碼,所以即是三個線程去獨立地完成賣票的任務;而在第二種方法中,咱們一樣也new了3個Thread對象,但只有一個Runnable對象,3個Thread對象共享這個Runnable對象中的代碼,所以,便會出現3個線程共同完成賣票任務的結果。若是咱們new出3個Runnable對象,做爲參數分別傳入3個Thread對象中,那麼3個線程便會獨立執行各自Runnable對象中的代碼,即3個線程各自賣5張票。
三、在第二種方法中,因爲3個Thread對象共同執行一個Runnable對象中的代碼,所以可能會形成線程的不安全,好比可能ticket會輸出-1(若是咱們System.out….語句前加上線程休眠操做,該狀況將頗有可能出現),這種狀況的出現是因爲,一個線程在判斷ticket爲1>0後,尚未來得及減1,另外一個線程已經將ticket減1,變爲了0,那麼接下來以前的線程再將ticket減1,便獲得了-1。這就須要加入同步操做(即互斥鎖),確保同一時刻只有一個線程在執行每次for循環中的操做。而在第一種方法中,並不須要加入同步操做,由於每一個線程執行本身Thread對象中的代碼,不存在多個線程共同執行同一個方法的狀況。
歡迎工做一到五年的Java工程師朋友們加入Java架構開發 : 867748702 羣內提供免費的Java架構學習資料(裏面有高可用、高併發、高性能及分佈式、 Jvm性能調優、Spring源碼,MyBatis,Netty,Redis,Kafka,Mysql,Zookeeper, Tomcat,Docker,Dubbo,Nginx等多個知識點的架構資料) 合理利用本身每一分每一秒的時間來學習提高本身, 不要再用"沒有時間「來掩飾本身思想上的懶惰!趁年輕,使勁拼,給將來的本身一個交代!