Java多線程實現方式主要有四種:繼承Thread類、實現Runnable接口、實現Callable接口經過FutureTask包裝器來建立Thread線程、使用ExecutorService、Callable、Future實現有返回結果的多線程。html
其中前兩種方式線程執行完後都沒有返回值,後兩種是帶返回值的。 java
使用Thread對象的interrupt()方法,打斷線程睡眠則會拋出interrupted異常git
System.in.read();讀取鍵盤輸入多線程
方式一:繼承Thread類(線程沒有返回值,在java.lang包中)less
重寫run()方法,調用start()方法執行。ide
須要注意的是:爲何多線程的啓動不是調用run()方法,而是調用start()方法?函數
在Java開發中有一門JNI(Java Native Interface)技術,這門技術的特色,使用Java調用本機操做系統的函數,可是這個技術不能離開特定的操做系統。測試
若是線程想要執行,須要操做系統分配資源。因此此操做嚴格來說須要JVM根據不一樣的操做系統來實現的。this
start()方法中,使用了native關鍵字修飾了方法,而native關鍵字時根據不一樣的操做系統分配不一樣的資源。url
start()方法,不單單要啓動多線程執行的代碼,還須要根據不一樣的操做系統來分配資源
1 package test; 2 3 public class MyThread { 4 public static void main(String[] args) { 5 Test t1 = new Test("one"); 6 Test t2 = new Test("two"); 7 Test t3 = new Test("three"); 8 /** 9 * 調用Thread類中的start方法,才能進行多線程的操做,而不是run方法 10 * start()方法不單單啓動多線程代碼的執行,還須要根據不一樣的操做系統分配資源 11 */ 12 try {//調用Thread類中的sleep方法,讓線程等待指定的一段時間 13 Thread.sleep(1000); 14 } catch (InterruptedException e) { 15 e.printStackTrace(); 16 } 17 t1.start(); 18 t2.start(); 19 t3.start(); 20 } 21 } 22 23 /** 24 * 繼承線程類Thread,重寫run()方法,在run方法中實現須要進行的數據操做 25 * @author Administrator 26 * 27 */ 28 class Test extends Thread{ 29 30 private String name; 31 32 public Test(String name) { 33 this.name=name; 34 } 35 @Override 36 public void run() {//須要進行多進程的操做 37 for (int i = 0; i < 100; i++) { 38 System.out.println(name+"===>"+i); 39 } 40 } 41 }
方式二:實現Runnable接口(線程沒有返回值,在java.lang包中)
該接口標註爲:@Java.lang.FactionInterface
實現run方法,將Runnable對象做爲參數放入到Thread構造方法中,在調用start()方法。
1 package test; 2 /** 3 * 測試Runnable接口 4 * @author Administrator 5 * 6 */ 7 public class MyRunnable { 8 public static void main(String[] args) { 9 Demo mr1 = new Demo("A"); 10 Demo mr2 = new Demo("B"); 11 Demo mr3 = new Demo("C"); 12 //將該對象做爲參數,傳入到Thread類中,在調用start()方法。 13 new Thread(mr1).start(); 14 new Thread(mr2).start(); 15 new Thread(mr3).start(); 16 } 17 } 18 19 /** 20 * 實現Runnable接口,實現多線程 21 * @author Administrator 22 * 23 */ 24 class Demo implements Runnable { 25 26 private String name; 27 28 public Demo(String name) { 29 this.name = name; 30 } 31 32 @Override 33 public void run() { 34 for (int i = 0; i < 300; i++) { 35 System.out.println(name + "==>" + i); 36 } 37 } 38 39 }
問題一:Thread與Runnable有什麼不一樣?
一、Thread實現了Runnable接口,使用Runnable接口能夠避免單根繼承的問題。
二、Runnable接口實現的多線程能夠比Thread類實現的多線程更加清楚的描述數據共享的概念。
問題二:寫出兩種多線程實現操做?
1 package test; 2 /** 3 * Runnable接口比Thread類更加清楚的描述了數據共享的概念 4 * @author Administrator 5 * 6 */ 7 public class ThreadAndRunnable { 8 9 public static void main(String [] args){ 10 TestDemo1 t = new TestDemo1(); 11 new Thread(t).start(); 12 new Thread(t).start(); 13 new Thread(t).start(); 14 try { 15 Thread.sleep(2000); 16 } catch (InterruptedException e) { 17 // TODO Auto-generated catch block 18 e.printStackTrace(); 19 } 20 System.out.println("=======================================我是分割線======================================="); 21 /** 22 * 這裏雖然也能夠數據共享, 23 * 可是,TestDemo2已經繼承了Thread類,而這裏又要new三個Thread類出來, 24 * 區調用start方法,顯得畫蛇添足 25 */ 26 TestDemo2 d1 = new TestDemo2(); 27 new Thread(d1).start(); 28 new Thread(d1).start(); 29 new Thread(d1).start(); 30 } 31 32 } 33 34 /** 35 * 實現了Runnable接口的類,能夠明顯的表示出數據共享的概念 36 * @author Administrator 37 * 38 */ 39 class TestDemo1 implements Runnable{ 40 /** 41 * 買票 42 */ 43 private int numb = 20; 44 45 @Override 46 public void run() { 47 for (int i = 0; i < 200; i++) { 48 if (this.numb > 0) { 49 System.out.println("買票;numb = "+this.numb--); 50 } 51 } 52 } 53 } 54 55 /** 56 * Thread類實現數據共享 57 * @author Administrator 58 * 59 */ 60 class TestDemo2 extends Thread{ 61 private int num = 20; 62 @Override 63 public void run() { 64 for (int i = 0; i < 200; i++) { 65 if(this.num > 0) 66 System.out.println("買票;num = "+this.num--); 67 } 68 } 69 70 }
方式三:實現Callable接口經過FutureTask包裝器來建立Thread線程(線程有返回值,該接口在java.util.concurrent包中)
1 @java.lang.FactionalInterface 2 public interface Callable<V>{ 3 public V call() throws Exception; 4 }
從JDK1.5開始提供一個類java.util.concurrentFutureTask<V>,這個類主要負責Callable接口對象操做的,該類的定義結構爲:
1 public class FutureTask<V> extends Object implements RunnableFuture<V>
2
3 //然而RunnableFuture有是什麼?
4 public interface RunnableFuture<V> extends Runnable,Future<V>
5
6 //然而FutureTask<V>接口的構造方法內,接受了Callable接口對象
7 public FutureTask(Callable<V> callable) 8 //接受callable對象的目的:取得call()方法的結果,只有經過FutureTask類才能獲得返回的 //結果
1 package test; 2 3 import java.util.concurrent.Callable; 4 import java.util.concurrent.FutureTask; 5 /** 6 * Callable接口實現多線程實例,能夠獲得返回的數據 7 * @author Administrator 8 * 9 */ 10 public class MyCllable { 11 12 public static void main(String[] args) throws Exception{ 13 TestDemo t1 = new TestDemo(); 14 TestDemo t2 = new TestDemo(); 15 FutureTask<String> task1 =new FutureTask<String>(t1); 16 FutureTask<String> task2 =new FutureTask<String>(t2); 17 /** 18 * FutureTask類是Runnable接口子類,因此能夠做爲構造參數調用start()方法 19 */ 20 new Thread(task1).start();//啓動多線程 21 new Thread(task2).start();//啓動多線程 22 System.out.println("task1===>"+task1.get());//獲得返回的結果 23 System.out.println("task2===>"+task2.get());//獲得返回的結果 24 } 25 26 } 27 28 class TestDemo implements Callable<String>{ 29 30 private int num = 20; 31 32 @Override 33 public String call() throws Exception { 34 for (int i = 0; i < 200; i++) { 35 if(this.num > 0){ 36 System.out.println("使用Callable接口實現多線程:"+num--); 37 } 38 } 39 return "數據歸零"; 40 } 41 42 }
示例:寫一個線程類輸出001—999啓動10條線程同時執行該類,每一個線程要都有機會,並且不能重複而其有序
1 package com.zelin.lesson.test; 2 3 import java.text.NumberFormat; 4 5 /** 6 * 編寫一個線程類,啓動10條線程同時執行該類,要求輸出效果以下所示 7 * 001 8 * 002 9 * 003 10 * …. 11 * 999 12 * 輸出001—999 每一個線程要都有機會,並且不能重複而其有序 13 */ 14 public class TestThread { 15 public static void main(String[] args) { 16 Thread0 t = new Thread0(); 17 for (int i = 0; i < 10; i++) { 18 new Thread(t).start(); 19 } 20 } 21 } 22 23 class Thread0 implements Runnable{ 24 //1.定義變量 25 private int tickets = 1; 26 @Override 27 public void run() { 28 while(true){ 29 synchronized (this){ 30 if(tickets == 1000) break; 31 //2.將變量進行格式化處理 32 NumberFormat numberFormat = NumberFormat.getInstance(); 33 //3.設置輸出的數字的最小整數位數 34 numberFormat.setMinimumIntegerDigits(3); 35 //4.對數字進行格式化處理 36 String format = numberFormat.format(tickets++); 37 //5.輸出 38 System.out.println(format); 39 } 40 } 41 } 42 }