一、線程:進程中負責程序執行的執行單元,線程自己依靠程序進行運行,線程是程序中的順序控制流,只能使用分配給程序的資源和環境;多線程
二、進程:執行中的程序,一個進程至少包含一個線程;ide
三、單線程:程序中只存在一個線程,實際上主方法就是一個主線程;函數
四、多線程:在一個程序中運行多個任務,目的是更好地使用CPU資源。this
Java中有兩種方法實現多線程:一、繼承Thread類 二、實現 Runnable 接口
Thread 類最重要的方法是 run(),它爲Thread 類的方法 start() 所調用,提供咱們的線程所要執行的代碼。 咱們在建立Thread 類的子類中重寫 run() ,加入線程所要執行的代碼便可。
1 public class MyThread extends Thread { 2 3 int count = 1; 4 int number; 5 6 public MyThread(int num) { 7 this.number = num; 8 System.out.println("建立線程 " + number); 9 } 10 11 @Override 12 public void run() { 13 while(true) { 14 System.out.println("線程 " + number + ": 計數" + count); 15 if(++count == 3) { 16 return; 17 } 18 } 19 } 20 21 public static void main(String[] args) { 22 for(int i=0; i<3; i++) { 23 new MyThread(i+1).start(); 24 } 25 } 26 27 }
輸出結果:spa
建立線程 1
建立線程 2
建立線程 3
線程 1: 計數1
線程 3: 計數1
線程 2: 計數1
線程 3: 計數2
線程 1: 計數2
線程 2: 計數2線程
Runnable 接口只有一個方法 run(),咱們聲明本身的類實現 Runnable 接口並提供這一方法,將咱們的線程代碼寫入其中,就完成了這一部分的任務。code
可是 Runnable 接口並無任何對線程的支持,咱們還必須建立 Thread 類的實例,這一點經過 Thread 類的構造函數public Thread(Runnable target)來實現。對象
1 public class MyRunnable implements Runnable{ 2 3 int count = 1; 4 int number; 5 6 public MyRunnable(int num) { 7 this.number = num; 8 System.out.println("建立線程 " + number); 9 } 10 11 @Override 12 public void run() { 13 while(true) { 14 System.out.println("線程 " + number + ": 計數" + count); 15 if(++count == 3) { 16 return; 17 } 18 } 19 } 20 21 public static void main(String[] args) { 22 for(int i=0; i<4; i++) { 23 new Thread(new MyRunnable(i+1)).start(); 24 } 25 } 26 }
輸出結果:blog
建立線程 1
建立線程 2
線程 1: 計數1
線程 1: 計數2
建立線程 3
線程 2: 計數1
線程 2: 計數2
建立線程 4
線程 3: 計數1
線程 3: 計數2
線程 4: 計數1
線程 4: 計數2繼承
一、適合多個相同程序代碼的線程去處理同一個資源
二、能夠避免因爲Java的單繼承性帶來的侷限性
三、加強了程序的健壯性,代碼可以被多個線程共享,代碼與數據是獨立的。
下面經過實現簡單的賣票場景來印證上述問題:
1 public class Tickets implements Runnable{ 2 3 private int ticket = 10; 4 5 @Override 6 public void run() { 7 for(int i=0; i<100; i++) { //定義一個超過票數的循環 8 if(ticket>0) { 9 System.out.println(Thread.currentThread().getName() + " sale:" + ticket--); //顯示餘票 10 } 11 } 12 } 13 14 /* 15 * 若是實例化兩個對象,好比實例化ticket1再實例化一個ticket2你會發現兩個不一樣的線程沒有共享ticket 16 * 可是若是MyThread是繼承Thread類而不是實現接口Runnable,下面的代碼將報錯。 17 * */ 18 public static void main(String[] args) { 19 Tickets ticket = new Tickets(); 20 Thread t1 = new Thread(ticket); 21 Thread t2 = new Thread(ticket); 22 Thread t3 = new Thread(ticket); 23 Thread t4 = new Thread(ticket); 24 t1.start(); 25 t2.start(); 26 t3.start(); 27 t4.start(); 28 } 29 30 }
輸出結果:
Thread-0 sale:10
Thread-3 sale:8
Thread-2 sale:9
Thread-2 sale:4
Thread-2 sale:3
Thread-2 sale:2
Thread-2 sale:1
Thread-3 sale:5
Thread-1 sale:6
Thread-0 sale:7
1 public class Tickets extends Thread { 2 3 private int ticket = 10; 4 5 @Override 6 public void run() { 7 for(int i=0; i<100; i++) { //定義一個超過票數的循環 8 if(ticket>0) { 9 System.out.println(Thread.currentThread().getName() + " sale:" + ticket--); //顯示餘票 10 } 11 } 12 } 13 14 /* 15 * 若是實例化兩個對象,好比實例化ticket1再實例化一個ticket2你會發現兩個不一樣的線程沒有共享ticket 16 * 可是若是MyThread是繼承Thread類而不是實現接口Runnable,下面的代碼將報錯。 17 * */ 18 public static void main(String[] args) { 19 Tickets ticket1 = new Tickets(); 20 Tickets ticket2 = new Tickets(); 21 ticket1.start(); 22 // ticket1.start(); //若是同時啓動兩個ticket1的線程,會報錯 23 ticket2.start(); 24 } 25 }
輸出結果:
Thread-1 sale:10Thread-0 sale:10Thread-1 sale:9Thread-0 sale:9Thread-1 sale:8Thread-0 sale:8Thread-1 sale:7Thread-0 sale:7Thread-1 sale:6Thread-0 sale:6Thread-1 sale:5Thread-0 sale:5Thread-1 sale:4Thread-0 sale:4Thread-1 sale:3Thread-0 sale:3Thread-0 sale:2Thread-1 sale:2Thread-0 sale:1Thread-1 sale:1