Java多線程的四種實現方式
1.Java多線程實現的方式有四種:
1.繼承Thread類,重寫run方法
2.實現Runnable接口,重寫run方法,實現Runnable接口的實現類的實例對象作為Thread構造函數的target
3.通過Callable和FutureTask創建線程
4.通過線程池創建線程
2.Thread實現方式
繼承Thread類,重寫run()方法,創建Thread對象調用start()方法啟動線程。
public class ThreadDemo extends Thread { @Override public void run() { int t = 1;for (int i = 0; i < 10; i++) { System.out.println(Thread.currentThread().getName() + " " + (t++)); } } public static void main(String[] args) { ThreadDemo td1 = new ThreadDemo(); ThreadDemo td2 = new ThreadDemo(); td1.setName("Thread1"); td2.setName("Thread2"); td1.start(); td2.start(); } }
結果:
3.Runnable實現方式
實現Runnable接口,實現run()方法,接口的實現類的實例作為Thread的target傳入帶參的Thread構造函數,調用start()方法啟動線程。
public class RunnableDemo implements Runnable { @Override public void run() { int t = 1; for (int i = 0; i < 10; i++) { System.out.println(Thread.currentThread().getName()+ " " + (t++)); } } public static void main(String[] args) { RunnableDemo rd = new RunnableDemo(); Thread tr1 = new Thread(rd); Thread tr2 = new Thread(rd); tr1.setName("Thread1"); tr2.setName("Thread2"); tr1.start(); tr2.start(); } } }
結果:
3.Callable和FutureTask創建線程實現方式
(1)創建Callable接口的實現類 ,並實現Call方法;
(2)創建Callable實現類的實現,使用FutureTask類包裝Callable對象,該FutureTask對象封裝了Callable對象的Call方法的返回值 ;
(3)使用FutureTask對象作為Thread對象的target創建並啟動線程;
(4)調用FutureTask對象的get()來獲取子線程執行結束的返回值。
import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.FutureTask; public class CallableFutureTaskDemo implements Callable<Integer> { @Override public Integer call() throws Exception { int t = 1; for (int i = 0; i < 10; i++) { System.out.println(Thread.currentThread().getName() + " " + (t++)); } return t; } public static void main(String[] args) { Callable<Integer> cftd1 = new CallableFutureTaskDemo(); Callable<Integer> cftd2 = new CallableFutureTaskDemo(); FutureTask<Integer> ft1 = new FutureTask<>(cftd1); FutureTask<Integer> ft2 = new FutureTask<>(cftd2); Thread t1 = new Thread(ft1); Thread t2 = new Thread(ft2); t1.setName("Thread1"); t2.setName("Thread2"); t1.start(); t2.start(); try { System.out.println(ft1.get()); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (ExecutionException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
結果:
5.線程池實現方式
import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class ExecutorDemo implements Runnable { private static int POOL_NUM = 2; //線程池數量 @Override public void run() { int t = 1; for (int i = 0; i < 10; i++) { System.out.println(Thread.currentThread().getName() + " " + (t++)); } } public static void main(String[] args) { ExecutorService executorService = Executors.newFixedThreadPool(3); for (int i = 0; i < POOL_NUM; i++) { ExecutorDemo ed = new ExecutorDemo(); executorService.execute(ed); } executorService.shutdown(); } }
結果:
java裏面的線程池的頂級接口是Executor,Executor並不是一個線程池,而只是一個執行線程的工具,而真正的線程池是ExecutorService。
java中的有哪些線程池?
1.newCachedThreadPool創建一個可緩存線程池程
2.newFixedThreadPool 創建一個定長線程池
3.newScheduledThreadPool 創建一個定長線程池
4.newSingleThreadExecutor 創建一個單線程化的線程池
這裏的例子用到的就是newFixedThreadPool 。
6.總結
(1)實現Runnable接口比繼承Thread類更具有優勢!Runnable接口適合多個相同的程序代碼的線程去處理同一個資源,可以避免java中的單繼承的限制,增加程序的健壯性,而且代碼可以被多個線程共享,實現代碼和數據獨立。
(2)使用線程池可以減少了創建和銷毀線程的次數,每個工作線程都可以被重復利用,可執行多個任務,可以根據系統的承受能力,調整線程池中工作線線程的數量。
(3)實際應用中,可以通過一個boolean標誌位來結束線程。
(4)ExecutorService、Callable都是屬於Executor框架。返回結果的線程是在JDK1.5中引入的新特征,還有Future接口也是屬於這個框架,有了這種特征得到返回值更方便。
執行Callable任務後,可以獲取一個Future的對象,在該對象上調用get就可以獲取到Callable任務返回的值(由泛型決定)了。get()方法是阻塞的,即線程無返回結果,get方法會一直等待。此外,ExecutoreService提供了submit()方法,傳遞一個Callable或Runnable,返回Future。如果Executor後臺線程池還沒有完成Callable的計算,這調用返回Future對象的get()方法,會阻塞直到計算完成。
Java多線程的四種實現方式