3.2.1 lambda
定义:lambda是匿名函数,基于数学中的λ演算得名。可使代码更加简洁。
Lambda表达式的语法
基本语法:
(parameters) -> expression
或
(parameters) ->{ statements; }
示例参考地址:Java Lambda表达式入门_java ->{-CSDN博客
https://blog.csdn.net/weixin_36755535/article/details/131350405
3.2.2 stream
就是一个“流”类
参考资料:Java--Stream流详解_java stream-CSDN博客
针对某个list中元素的非String属性提取出来组成逗号分隔的字符串
String collect = users.stream().map(User::getId).map(String::valueOf).collect(Collectors.joining(","));
3.2.3 流式编程
基于Stream类对集合进行一系列操作
参考资料:https://blog.csdn.net/JokerLJG/article/details/122693051
3.2.4 函数式编程
定义:函数式编程是一种编程规范,也就是如何编写程序的方法论,属于结构化编程的一种,主要思想是将运算过程尽量写成一系列嵌套的函数调用。
优点:代码简洁,开发快速;接近自然语言,易于理解;更方便代码管理;易于并发编程;代码热升级
参考资料:百度百度-函数式编程
参考资料:Java 函数式编程_java new thread-CSDN博客
Supplier接口:获得结果
- T get():获得结果
- 该方法不需要参数,它会按照某种实现逻辑(由Lambda表达式实现)返回一个数据
- Supplier 接口也被称为生产型接口,如果我们指定了接口的泛型是什么类型,那么接口中的get方法就会生产什么类型的数据供我们使用
Consumer接口:对参数进行指定的处理
Consumer:包含两个方法
void accept(T t):对给定的参数执行此操作
default Consumer andThen(Consumer after):返回一个组合的Consumer,依次执行此操作,然后执行after操作
Consumer 接口也被称为消费型接口,它消费的数据类型由泛型指定
Predicate接口
boolean test(T t) 对给定的参数进行判断(判断逻辑由Lambda表达式实现),返回一个布尔值
Function接口
Function<T,R>两个常用方法
R apply(T t) 将此函数应用于给定的参数
default Function<T,V> andThen(Function after) 返回一个组合函数,首先将该函数应用于其输入,然后将 after函数应用于结果
3.2.5 反应式编程
定义:反应式编程是一种编程思想、编程方式,为了简化并发编程而出现的。与传统处理方式相比,可基于数据流中的事件进行反应处理。
反应式编程更强调异步非阻塞。
参考资料:https://blog.csdn.net/qq_42799615/article/details/111235576
3.2.6 线程池
线程池概念:创建java线程需要给对象分配栈堆内存和初始化内存,频繁的创建和销毁线程会大大降低系统的运行效率,采用线程池可提升性能(线程池独自负责线程的创建、维护、分配)和更好的管理线程(每个线程池会保存一些基本的线程信息,对线程进行管理)。
JUC线程池架构:
Executor(接口)、ExecutorService(接口)、AbstractExecutorService(抽象类)、ThreadPoolExecutor(JUC线程池核心实现类)、ScheduledExecutorService(延时性和周期性的接口)、ScheduledThreadPoolExecutor(延时执行和周期执行类)、Executors(静态工厂类、调用静态方法获取线程池实例对象)
Executors创建线程的4中方法:
单线程化线程池:按照提交次序顺序执行;唯一线程存活时间无限;适用于任务提交按照次序,任务逐一进行的场景。
缺点:阻塞队列无界,如果队列很大,很有可能导致JVM出现OOM(内存资源耗尽)
ExecutorService executorService = Executors.newSingleThreadExecutor();
固定数量线程池:线程数量固定,如果没有达到固定的线程数量,如果有新的任务进来,会开辟新的线程,直至达到规定的线程数量;线程一旦达到固定数量就会保持不变,如果某个线程因异常而结束,会补充新的线程;如果所有线程处于繁忙,新任务会将进入阻塞队列中。
适用于需要任务长期执行和CPU密集型任务。
缺点:内部使用无界队列来存放排队任务,当大量任务超过线程池最大容量需要处理时,队列无限增大,使服务器资源迅速耗尽
ExecutorService executorService1 = Executors.newFixedThreadPool(3);
可缓存线程池:有新任务进来时,如果所有线程繁忙,则会开辟新的线程;线程池大小不会限制,依赖与JVM或操作系统能创建的最大线程大小;如果部分线程空闲(60秒不执行任务)则会进行回收线程。
适用于快速处理突发性强、耗时较短的任务场景。例如REST API的瞬时削峰场景。
缺点:线程池没有最大线程数量限制,如果大量异步任务执行目标实例同时提交,可能会因线程创建过多导致CPU资源耗尽。
ExecutorService executorService = Executors.newCachedThreadPool();
可调度线程池:延时性、周期性
ScheduledExecutorService pool=Executors.newScheduledThreadPool(2);
pool.scheduleAtFixedRate(new MyThread(), 0, 500, TimeUnit.MILLISECONDS);
缺点:线程数无上限
Executors创建线程存在的问题:
单线程线程池、固定线程线程池:阻塞队列无界,会堆积大量任务导致OOM
可缓存线程池、可调度线程池: 线程数量无限制,会创建大量线程导致OOM
可直接使用线程池ThreadPoolExecutor的构造器。
线程池任务调度流程:
当前线程工作数量小于核心线程数量,则优先创建线程
线程池中任务数量大于核心线程数量,新任务被加入阻塞队列中,直到阻塞队列加满为止
当完成一个任务,执行器优先从阻塞队列中获取任务执行,直到阻塞队列为空
当核心线程用完,阻塞队列已满,会一直创建新线程去执行新任务,直到线程总数超过最大线程数量。
如果池中线程数量超过最大线程数量,线程池会拒绝接收任务,执行拒绝策略。
ThreadFactory称之为线程工厂类,用于创建线程。
Executors称之为线程池工厂类,用于创建线程池。
线程工厂:ThreadFactory是线程工厂接口,只有一个方法newThread,调用此方法时可更改线程的名称、线程组、优先级、守护线程等
任务阻塞队列:线程从空阻塞队列中获取元素时,线程会被阻塞,直至阻塞队列有元素,被阻塞线程会自动执行。
调度器钩子方法:前置钩子、后置钩子、线程池终止时钩子。分别是beforeExecutor、afterExecutor、terminated方法。
线程池拒绝策略:拒绝情况包括线程池关闭、工作队列和线程池最大线程容量都满。
常见的几种拒绝策略:
AbortPolicy:有新任务就会被拒绝,并且抛出RejectedExecutionException。默认策略
DiscardPolicy:抛弃策略。有新任务直接丢掉,并无异常
DiscardOldestPolicy:抛弃最早进入队列的任务,从队列中腾出空间,加入新的队列
CallerRunPolicy:调用者执行策略。新任务进入线程池失败,则提交任务线程会自己去执行任务,不会使用线程池中的线程。
自定义策略:编写类,实现RejectExecutionException接口,重写rejectedExecution方法
线程池关闭:
线程池5种类状态:
RUNNING:创建之后初始化状态,可执行任务
SHUTDOWN:此状态不会接收新任务,但是队列中的任务会执行完毕
STOP:不接受新任务、中断未处理任务、中断所有工作线程
TIDYING:所有任务已结束或处理完成,将会执行terminated方法
TERMINATED:执行完terminated方法之后的状态
参考资料:https://blog.csdn.net/qq_43478694/article/details/123385279
3.2.7 异步编程
定义:就是将业务中关联性不强的进行拆分,使其同时执行,是程序并发运行的一种手段,允许多个事件同时发生,当程序调用需要长时间运行的方法时,它不会阻塞当前的执行流程,程序可以继续运行。
异步处理是不用阻塞当前线程来等待处理完成,而是进行后续操作,直至其他线程处理结束,回调通知此线程。
异步、多线程、并行并非相同概念。
多线程是对CPU剩余劳动力的压榨,是一种技术,强调的是并发。
异步强调的是非阻塞,是一种编程模式。
并行虽然也是对CPU剩余劳动价值的压榨,且基于多线程入伍,但它强调的是高效完成计算任务,而不是并发数量。
并发和并行的区别:并发强调的是有处理多个任务的能力;并行强调的是有同时处理多个任务的能力。
最简单使用异步编程的方式就是创建1个线程来实现。
参考资料:https://blog.csdn.net/m0_58821619/article/details/117979239
https://www.zhihu.com/question/33515481/answer/58849148
https://blog.csdn.net/AS011x/article/details/126931651
3.2.8 网络编程AIO/NIO/BIO
同步定义:多线程并发访问共享数据时,保证共享数据在同一时间只被一个线程使用。
BIO:同步阻塞IO。此网络编程基本模型是C/S模型,即两进程之间的通信。此模型最大问题是缺乏弹性伸缩能力,客户端访问量激增后,服务端线程和客户端呈1:1的正比关系,随着访问量持续增大,其他接入的消息,只能一直等待,甚至系统会死掉。
NIO:非阻塞IO。支持阻塞和非阻塞两种形式。NIO提供了与传统BIO模型中的Socket和ServerSocket相对应的SocketChannel和ServerSocketChannel两种不同的套接字通道实现。
相对高负载、高并发的网络应用,更适合非阻塞IO来开发。
缓冲区buffer:一个包含写入或读取数据的对象;在NIO库中,所有数据都是在缓冲区处理的;缓冲区实际上是一个数组,并提供了对数据结构化访问和维护读写位置等信息;
具体的缓冲区有:ByteByffer、CharBuffer、ShortByffer、IntBuffer、LongBuffer、FloatBuffer、DoubleBuffer。都实现了Buffer接口。
通道channel:数据的读取和写入需要经过channel。就像一个双向通道,可用于读、写、读写同时操作。
channel分两类:
SelectableChannel:用户网络读写
FileChannel:用于文件操作
SocketChannel和ServerSocketChannel都是SelectableChannel的子类。
多路复用器Selector:是NIO编程的基础。Selector提供选择就绪任务的能力,会不断轮询注册在其上的channel,如果某个channel上发生读写事件,就会被selector轮询出来,然后通过SelectionKey获取就绪channel的集合,进行后续的I/O操作。一个Selector可以同时轮询多个channel。因此只需要一个线程负责Selector的轮询,就可以接入成千上万客户端。
事件驱动IO:AIO
NIO的2.0版本,引入了异步通道的概念,并提供了异步文件通道和异步套接字通道的实现。
异步套接字通道,是真正的异步非阻塞IO。无需过多的Selector对注册的通道进行轮询即可实现异步读写,简化NIO的编程模型。
参考资料:Java 网络IO编程总结(BIO、NIO、AIO均含完整实例代码)_java bio-CSDN博客
https://blog.csdn.net/qq_35190492/article/details/113174359