线程的创建、Lambda函数式接口?Runnable和Callable之间的适配?动态修改线程任务?这里带你图解Java线程池
Java线程创建的方式
- 继承Thread类,重写run方法
- 重写Runnable接口,交给Tread类静态代理实现
- 实现Callable接口,用FutureTask封装
- 实现Runnable接口,用FutureTask封装
- 继承FutureTask类,重写run方法(猜想、偏方,你非要实现其实也可以,hhh)
- 线程池创建
前三种创建方式
这里为了便于叙述,毕竟不是本次的重点,我直接上源码,没基础的可以去找些其他资料来补一补
public class ThreadpoolApplication {
public static void main(String[] args) throws ExecutionException, InterruptedException {
// 1. 继承Thread类实现
Thread impl =new ThreadImpl();
impl.start();
// 2. 实现Runnable接口
// 对于有 @FunctionalInterface 的类 or 接口,我们可以使用lambda表达式来简化,当然
// 没有这个注解也可以,但是一定要符合函数式编程的规范
// 1. 只能有1个待实现的方法
// 2. 允许有默认方法
// 3. 只能是接口
// @FunctionalInterface 可有可无,但是为了规范建议写上,起一个标记作用,告诉编译器这是一个函数式接口
// 可以让IDE帮你检测你的函数式接口是否符合规范
Thread runnableImpl = new Thread(new Runnable() {
// 这里可以用函数式接口lambda表达式来简写,具体的内容这里不做过多解释,
// 你可以理解lambda实现为是对接口的简单实现,因为你用lambda返回的也是个Runnable实现对象
// 后面我就直接用Lambda表达式来简写了。
@Override
public void run() {
}
});
runnableImpl.start();
// 实现Callable接口,带返回值
FutureTask futureTask= new FutureTask(()->{
return 1;
});
new Thread(futureTask).start();
System.out.println(futureTask.get());
Integer result=0;
// 实现Runnable接口,带返回值
futureTask=new FutureTask(()->{
},result);
new Thread(futureTask).start();
futureTask.get(); // 其实这个值就是你设置的值,可以去看一下源码,这里只是为了方便任务管理
return ;
}
}
浅说函数式编程 —— Lambda的魔法
大家可能对函数式编程有点懵,其实就是符合上面所说的规范
对于有 @FunctionalInterface 的类 or 接口,我们可以使用lambda表达式来简化,当然没有这个注解也可以,但是一定要符合函数式编程的规范
- 只能有1个待实现的方法
- 允许有默认方法
- 只能是接口,抽象类也不行
@FunctionalInterface 可有可无,但是为了规范建议写上,起一个标记作用,告诉编译器这是一个函数式接口可以让IDE帮你检测你的函数式接口是否符合规范
比如这样子:
@FunctionalInterface
public interface MethodInterface {
void print();
default MethodInterface andThen(MethodInterface methodInterface){
// 想一下有什么区别
// print();
// methodInterface.print();
// return methodInterface;
return ()->{
print();
methodInterface.print();;
};
// 不用lambda表达式,那么就是在andThen里面进行执行的,每次执行andThen的时候都会自动执行print方法,而且总体上每次
// methodInterface.print()会执行两次,那么methodInterface.print()不写的话最后需要再执行一次applay
// 如果你是使用的lambda表达式返回,那么返回的是一个全新的接口,如果我们需要链式调用完,那么在最后还要执行一下
// print方法,当然你也可以选择实现一个end()方法来表示结束,相当于另外起一个名
}
}
其实上面的函数式接口和Cusumer一样,不过Cusumer多了一个判空的过程,除此之外还有另外几个常用的函数式接口(统一规范),如下:
Cusumer
@FunctionalInterface
public interface Consumer {
void accept(T t);
default Consumer andThen(Consumer