之前你們寫的都是單線程的程序,全是在main函數中調用方法,能夠清楚的看到它的效率是特別低的,就像python中使用單線程取爬一個網站,能夠說能讓你等的吐血,由於數據量實在太大了,今天咱們就來看看java的併發編程多線程的學習html
建立一個線程能夠有多種方法,好比繼承Thread類,實現Runnable接口......下面咱們來詳細的看看建立的方法java
爲何繼承
Thread
能夠直接調用start()
方法啓動線程呢,由於start()
自己就是Thread的方法,也就是繼承了Thread的start()方法,所以這個類的對象能夠調用start()啓動線程python
//繼承Thread public class MyThread extends Thread { public void run() { for (int i = 0; i < 10; i++) { System.out.println(this.getName()+"正在跑"); } } } public class Test{ public static void main(String[] args) { Mythread t1=new MyThread(); //建立對象 t1.start(); //啓動線程 } }
注意: 繼承
Thread
類的建立方法一個對象只能建立一個線程,並不能多個線程共用一個對象,只能一個線程對應一個對象,所以咱們來看看實現Runnable
接口的類來實現多個線程共享同一個對象編程
//實現Runnable接口 public class Demo implements Runnable { @Override public void run() { for(int i=0;i<10;i++) { System.out.println(Thread.currentThread().getName()+"正在跑"); } } } //測試類 public class Test{ public static void main(String[] args) { Demo d=new Demo(); //建立對象 Thread thread1=new Thread(d); //爲對象建立一個線程 Thread thread2=new Thread(d); //建立另一個線程 //同時啓動兩個線程 thread1.start(); thread2.start(); } }
從上面能夠清楚的看到實現
Runnable
接口的類一個對象能夠供多個線程共享,並不像繼承Thread類只爲一個線程使用多線程
直接在
main
方法中建立,若是建立的普通類的對象在外面,那麼必須是final修飾,能夠實現多個線程同時共享一個對象,這個和實現Runnable
接口同樣,這時候就要控制同步條件了,若是在run方法中定義對象,那麼,就是一個線程對應一個對象,這個就和繼承Thread類同樣的效果。因此能夠根據條件自由選擇併發
//普通的一個類 public class Simple { public void display() { for(int i=0;i<10;i++) { System.out.println(Thread.currentThread().getName()+"正在跑"); } } } //線程測試類 public class Test { public static void main(String[] args) { //若是在外面必須使用final,固然也能夠直寫在run方法中,不過寫在外面能夠實現多個線程共享一個對象 //寫在run方法中當前對象只能爲一個線程使用,和繼承Thread類同樣的效果 final Simple simple=new Simple(); //下面建立使用同一個對象建立同兩個線程,實現多個線程共享一個對象,和實現Runnable接口同樣的效果 Thread t1=new Thread(){ public void run() { simple.display(); }; }; Thread t2=new Thread(){ public void run() { simple.display(); }; }; //啓動這兩個線程 t1.start(); t2.start(); }}
static void sleep(long mils)
使正在運行的線程休眠mils毫秒,可是這裏須要注意的是若是線程加了鎖,那麼使線程休眠並不會釋放鎖
String getName()
獲得線程的名稱,上面的程序中已經使用了這個方法
void setName(String name)
設置正在運行的線程的名字爲name
start()
啓動線程,線程的建立並不意味着線程的啓動,只有調用start()方法線程纔是真正的開始運行
long getId()
返回線程的標識符
run()
線程執行的代碼都放在run()方法中,在run方法中的調用是有序的,都是按照程序運行的順序開始執行
下面使用上面的方法建立一個實例ide
//線程的類,繼承Thread public class MyThread1 extends Thread { public void run() { // 重載run方法,而且在其中寫線程執行的代碼塊 for (int i = 0; i < 10; i++) { // 獲取線程的id和name System.out.println("Thread-Name: " + this.getName() + " Thread-id: " + this.getId()); try { this.sleep(1000); // 線程休眠1秒 } catch (InterruptedException e) { e.printStackTrace(); } } } } //線程測試的類 public class Test { public static void main(String[] args) { MyThread1 t1 = new MyThread1(); // 建立線程 t1.setName("第一個線程"); // 設置線程的名字 MyThread1 t2 = new MyThread1(); t2.setName("第二個線程"); t1.start(); // 啓動線程,開始運行 t2.start(); } }
void join()
等待該線程終止才能運行其餘的線程void join(long mils)
等待該線程的時間爲mils毫秒,一旦過了這個時間其餘線程正常執行
//線程類 public class MyThread1 extends Thread { public void run() { // 重載run方法,而且在其中寫線程執行的代碼塊 for (int i = 0; i < 10; i++) { // 獲取線程的id和name System.out.println("Thread-Name: " + this.getName() + " Thread-id: " + this.getId()); try { this.sleep(1000); // 線程休眠1秒 } catch (InterruptedException e) { e.printStackTrace(); } } } } //測試類 public class Test { public static void main(String[] args) { MyThread1 t1 = new MyThread1(); // 建立線程 t1.setName("第一個線程"); // 設置線程的名字 t1.start(); // 啓動線程,開始運行 try { t1.join(); //阻塞其餘線程,只有當這個線程運行完以後纔開始運行其餘的線程 } catch (InterruptedException e) { e.printStackTrace(); } for (int i = 0; i < 10; i++) { System.out.println("主線程正在運行"); } } } //輸出結果 /* Thread-Name: 第一個線程 Thread-id: 9 Thread-Name: 第一個線程 Thread-id: 9 Thread-Name: 第一個線程 Thread-id: 9 Thread-Name: 第一個線程 Thread-id: 9 Thread-Name: 第一個線程 Thread-id: 9 Thread-Name: 第一個線程 Thread-id: 9 Thread-Name: 第一個線程 Thread-id: 9 Thread-Name: 第一個線程 Thread-id: 9 Thread-Name: 第一個線程 Thread-id: 9 Thread-Name: 第一個線程 Thread-id: 9 主線程正在運行 主線程正在運行 主線程正在運行 主線程正在運行 主線程正在運行 主線程正在運行 主線程正在運行 主線程正在運行 主線程正在運行 主線程正在運行 */
getPriority()
獲得當前線程優先級setPriority(int num)
更改線程的優先級(0-10)默認的是5,優先級越高得到cpu資源的概率就會越高
//線程類 public class MyThread1 extends Thread { public void run() { // 重載run方法,而且在其中寫線程執行的代碼塊 for (int i = 0; i < 10; i++) { // 獲取線程的id和name System.out.println("Thread-Name: " + this.getName() + " Thread-id: " + this.getId()); try { this.sleep(1000); // 線程休眠1秒 } catch (InterruptedException e) { e.printStackTrace(); } } } } //測試類 public class Test { public static void main(String[] args) { MyThread1 t1 = new MyThread1(); // 建立線程 t1.setName("第一個線程"); // 設置線程的名字 MyThread1 t2 = new MyThread1(); t2.setName("第二個線程"); t2.setPriority(8); //設置第二個線程的優先級爲8,第一個線程的優先級爲5(是默認的) t1.start(); t2.start(); } } /* * 從上面的運行結果能夠看出大部分的第二個線程都是在第一個線程以前開始執行的,也就是說優先級越高得到cpu執行的概率就越大 * /
setDaemon(boolean)
是否設置爲守護線程,若是設置爲守護線程,那麼主線程銷燬守護線程也會隨之銷燬isDaemon()
判斷是否爲守護線程
//測試類 public class MyThread1 extends Thread { public void run() { // 重載run方法,而且在其中寫線程執行的代碼塊 for (int i = 0; i < 10; i++) { // 獲取線程的id和name System.out.println("Thread-Name: " + this.getName() + " Thread-id: " + this.getId()); try { Thread.sleep(1000); //休眠一秒,方便主線程運行結束 } catch (InterruptedException e) { e.printStackTrace(); } } } } public class Test { public static void main(String[] args) { MyThread1 t1 = new MyThread1(); // 建立線程 t1.setName("第一個線程"); // 設置線程的名字 t1.setDaemon(true); t1.start(); for (int i = 0; i < 1; i++) { System.out.println(i); } } } //結果: /* 0 1 2 3 4 5 6 7 8 9 Thread-Name: 第一個線程 Thread-id: 9 */ /* * 從上面的結果能夠看出,一旦主線程結束,那麼守護線程就會自動的結束 * /