1:Callable實現類介紹
首先我們都知道,在Java中最常見的是繼承Thread類和實現Runnable接口來實現多線程(
這里我推薦采用實現接口的方式來實現多線程,原因有兩點:
1、Java的設計是單繼承的設計,如果采用繼承Thread的方式實現多線程,則不能繼承其他的類。
2、采用接口能夠更好的實現數據共享。線程的啟動需要Thread類的start方法,如果采用繼承的方式每次新建一個線程時,每個新建線程的數據都會單獨的存在線程內存中,這樣每個線程會單獨的操作自己線程的數據,不能更好的實現線程之間的數據共享)
但是無論以上哪種方式實現多線程,都存在一個問題,就是線程run方法沒有返回值,如果一個線程需要有返回值時,可以采用本章講的實現Callable接口來實現多線程
首先看一下Callable接口的源碼
1 @FunctionalInterface 2 public interface Callable<V> { 3 /** 4 * Computes a result, or throws an exception if unable to do so. 5 * 6 * @return computed result 7 * @throws Exception if unable to compute a result 8 */ 9 V call() throws Exception; 10 }
首先明確一點這是一個函數式接口,其中的@FunctionalInterface定義了這個接口為函數式接口(具體函數式接口和普通接口有何區別可以自行查閱相關資料) ,Callable接口接受一個泛型作為接口中call方法的返回值類型,因此我們在使用時需要傳入一個返回值類型。
然后我去實現這個接口來定義我自己的線程類,這里我傳入了一個String類型作為接口call方法的返回值類型,然后實現了call方法,將result作為返回結果返回
1 public class MyCallable<String> implements Callable<String> { 2 3 private int tickt=10; 4 5 @Override 6 public String call() throws Exception { 7 // TODO Auto-generated method stub 8 String result; 9 while(tickt>0) { 10 System.out.println("票還剩余:"+tickt); 11 tickt--; 12 } 13 result=(String) "票已賣光"; 14 return result; 15 } 16 17 }
下面就看一下怎樣啟動采用實現Callable接口的線程
1 package Multi_Thread; 2 import org.apache.commons.io.FileUtils; 3 4 import java.io.File; 5 import java.io.IOException; 6 import java.net.URL; 7 import java.util.concurrent.*; 8 9 /** 10 * 實現callable接口 11 */ 12 public class CallMethod implements Callable<Boolean> { 13 String url; 14 String name; 15 16 public CallMethod(String url, String name) { 17 this.url = url; 18 this.name = name; 19 } 20 21 @Override 22 public Boolean call() { 23 WebDownloader down = new WebDownloader(); 24 try { 25 down.downloader(url,name); 26 } catch (IOException e) { 27 e.printStackTrace(); 28 } 29 return null; 30 } 31 class WebDownloader 32 { 33 public void downloader(String url,String name) throws IOException { 34 FileUtils.copyURLToFile(new URL(url),new File(name)); 35 } 36 } 37 38 public static void main(String[] args) throws ExecutionException, InterruptedException { 39 CallMethod callMethod = new CallMethod("https://csdnimg.cn/medal/github@240.png","a.png"); 40 //創建執行服務 41 ExecutorService executorService = Executors.newFixedThreadPool(1); 42 //提交執行 43 Future<Boolean> submit = executorService.submit(callMethod); 44 //獲取jieguo 45 Boolean aBoolean = submit.get(); 46 System.out.println(aBoolean); 47 executorService.shutdown(); 48 49 } 50 }
2:函數式接口
1. 函數式接口是個啥?
它是一個接口,在這個接口里面只能有一個抽象方法(但可以包含多個默認方法、靜態方法、繼承自Object的公有方法)。主要用於方法引用以及結合Lambda表達式使用。
2. 怎么定義?
@FunctionalInterface public Interface MyFunction { public void do(); //也可以包含如下方法 //默認方法 default void ddo() { //do what you want } //靜態方法 public static void sdo() { //do what you want } //繼承自Object的公有方法 @Override public boolean equals(Object obj); } 3. 怎么用? public void main(String[] args) { MyFunction mf = ()-> System.out.println("我是do方法");//l這個lambda表達式相當於實現了接口中的抽象方法, mf.do(); } 輸出: 我是do方法
注意:JDK7及其以下版本JDK只能包含公開且抽象的方法(默認由public abstract修飾),而JDK8開始可以包含default、static修飾的非抽象方法。