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修饰的非抽象方法。