Spring中的线程池
盘点Spring中的线程池,及如何在Spring异步任务使用自定义的线程池。
Spring中的内置线程池SimpleAsyncTaskExecutor实现了TaskExecutor接口,为每个任务创建一个线程,并异步执行它,可以通过setConcurrencyLimit设置最大的创建线程数,不适用大量执行时间短的任务。
SyncTaskExecutor同步的,谁调用谁执行,一般用于测试。
1234public void execute(Runnable task) { Assert.notNull(task, "Runnable must not be null"); task.run();}
ConcurrentTaskExecutorExecutor的适配类,暴露出Spring的TaskExecutor类。不推荐直接使用。
ThreadPoolTaskExecutor最常用,对java.util.concurrent.ThreadPoolExecutor的包装,可以运行时指定线程池的大小。
Spring定时调度定时调度的配置和 ...
线程池原理
线程池是基于一种池化思想管理线程的工具,类似于数据库连接池、内存池,为了减少多线程程序中频繁创建、销毁、调度线程带来的额外开销,带来如下好处:
降低资源的消耗,通过服用线程,减少线程的创建和销毁的开销;
提高响应速度,任务到来时,无需等待线程创建即可直接执行;
提高线程的可管理性,对线程资源进行统一的管控;
Java中的线程池Java中的线程池核心实现类是ThreadPoolExecutor,实现的顶层接口是Executor,顶层接口Executor提供了一种思想:将任务提交和任务执行进行解耦。用户无需关注如何创建线程,如何调度线程来执行任务,用户只需提供Runnable对象,将任务的运行逻辑提交到执行器(Executor)中,由Executor框架完成线程的调配和任务的执行部分。ExecutorService接口增加了一些能力:(1)扩充执行任务的能力,补充可以为一个或一批异步任务生成Future的方法;(2)提供了管控线程池的方法,比如停止线程池的运行。AbstractExecutorService则是上层的抽象类,将执行任务的流程串联了起来,保证下层的实现只需关注一个执 ...
服务端推送技术
有的时候服务端需要向客户端推送数据,比如聊天,通知等。有多种服务端推送消息的技术,比如简单的轮询,websocket协议,sse,各有千秋。
现状轮询websocketsseSSE全称Server-sent Events,是HTML 5 规范的一个组成部分。主要由两个部分组成:第一个部分是服务器端与浏览器端之间的通讯协议,第二部分则是在浏览器端可供 JavaScript 使用的 EventSource 对象。通讯协议是基于纯文本的简单协议。服务器端的响应的内容类型是“text/event-stream”。响应文本的内容可以看成是一个事件流,由不同的事件所组成。每个事件由类型和数据两部分组成,同时每个事件可以有一个可选的标识符。不同事件的内容之间通过仅包含回车符和换行符的空行(“\r\n”)来分隔。每个事件的数据可能由多行组成。
Spring切面在对象内部方法调用中无效
在一个对象中,两个方法互相调用,那么其中的切面是不会生效的。比如在一个方法中声明了缓存注解,另一个方法再去调用,那么就有可能不会生效。
场景出现这种情况的原因:在使用Spring AOP的时候,我们从 IOC 容器中获取的 Bean 对象其实都是代理对象,而不是那些 Bean 对象本身,而当在自己的 Service 类中使用 this 关键字嵌套调用同类中的其他方法时,由于 this 关键字引用的并不是该 Service Bean 对象的代理对象,而是其本身,故Spring AOP是不能拦截到这些被嵌套调用的方法的。
解决方法
写一个方法类获取容器中的bean,手动用获取的bean进行调用;
将当前代理类暴露给线程使用,显示调用代理对象,比如配置:<aop:aspectj-autoproxy expose-proxy="true" />或者Springboot添加配置注解@EnableAspectJAutoProxy(exposeProxy=true),然后使用方法获取代理类:UserServiceImpl service = AopContext. ...
高性能队列-Disruptor
Disruptor是英国外汇交易公司LMAX开发的一个高性能队列,研发的初衷是解决内存队列的延迟问题(在性能测试中发现竟然与I/O操作处于同样的数量级)。基于Disruptor开发的系统单线程能支撑每秒600万订单,2010年在QCon演讲后,获得了业界关注。2011年,企业应用软件专家Martin Fowler专门撰写长文介绍。同年它还获得了Oracle官方的Duke大奖。目前,包括Apache Storm、Camel、Log4j 2在内的很多知名项目都应用了Disruptor以获取高性能。需要特别指出的是,这里所说的队列是系统内部的内存队列,而不是Kafka这样的分布式队列。以下的队列都单一系统内的队列。
传统队列的问题传统队列的分类队列的底层数据结构一般分成三种:数组、链表和堆。在稳定性和性能要求特别高的系统中,为了防止生产者速度过快,导致内存溢出,只能选择有界队列;同时,为了减少 Java 的垃圾回收对系统性能的影响,会尽量选择 array/heap 格式的数据结构。这样筛选下来,符合条件的队列就只有 ArrayBlockingQueue。
出现的问题ArrayBlocki ...
Kafka多线程消费
当Kafka的生产速度大于消费速度的时候,会出现消息挤压,这时可以用多线程提高消费能力。而KafkaConsumer不支持多线程并发访问,否则会报ConcurrentmodificationException的异常。有两种方法发挥多线程消费的能力。
第一种方法,多个KafkaConsumer实例模型结构如下图:每个线程都有一个consumer实例,线程的个数取决于分区的个数,不能超过分区数,超过也没用,每个线程处理一个分区,相互不干扰。
第二种方法,多线程处理消费的结果模型结构如下图:也支持多个Consumer线程,每个consumer消费的数据又交给多线程去处理。
优缺点
方法
优点
缺点
第一种
实现简单,无需多线程同步;保证每个分区数据的有序性
线程数受分区数限制
第二种
并发扩展方便,并发度高
多线程需要相互协调,不能保证消息的有序性
实例配置文件
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657 ...
Kafka高性能的原因
Kafka读写快的原因分析。
分区充分利用集群的优势,提升io性能。
顺序写磁盘Kafka 的整个设计中,Partition 相当于一个非常长的数组,而 Broker 接收到的所有消息顺序写入这个大数组中。同时 Consumer 通过 Offset 顺序消费这些数据,并且不删除已经消费的数据,从而避免了随机写磁盘的过程。而删除过程,并非通过使用“读 - 写”模式去修改文件,而是将 Partition 分为多个 Segment,每个 Segment 对应一个物理文件,通过删除整个文件的方式去删除 Partition 内的数据。这种方式清除旧数据的方式,也避免了对文件的随机写操作。
充分利用PageCache引入 Cache 层的目的是为了提高 Linux 操作系统对磁盘访问的性能。Cache 层在内存中缓存了磁盘上的部分数据。当数据的请求到达时,如果在 Cache 中存在该数据且是最新的,则直接将数据传递给用户程序,免除了对底层磁盘的操作,提高了性能。
使用 Page Cache 的好处:
I/O Scheduler 会将连续的小块写组装成大块的物理写从而提高性能
I/O Sche ...
JavaIO模型
输入输出(IO)是指计算机同任何外部设备之间的数据传递。常见的输入输出设备有文件、键盘、打印机、屏幕等。数据可以按记录(或称数据块)的方式传递,也可以用流的方式传递。在socket编程中,需要读取和输出数据,这就用到了IO模型。Java在1.4之前用到的是同步阻塞的方式,性能存在瓶颈,后来又出现了非阻塞io,再后来1.7之后,又出现了AIO,总体来说这三类IO模型。
几种概念同步和异步
同步 概念:发送一个IO请求,等待着IO结果的返回,在此期间不能再发请求。
异步 概念:发送一个IO请求后,不需要等待,可以随时发送请求或者做其他事情,io完成后通知用户进程。
IO操作主要分为两个步骤,即发起IO请求和实际IO操作,同步与异步的区别就在于第二个步骤是否阻塞请求进程。若实际IO操作阻塞请求进程,即请求进程需要等待或者轮询查看IO操作是否就绪,则为同步IO;若实 IO操作并不阻塞请求进程,而是由操作系统来进行实际IO操作并将结果返回,则为异步IO。
阻塞和非阻塞
阻塞 概念:一个线程调用read()或者write()方法时,该线程将被阻塞,直到有一些数据读读取或者被写入,在此期 ...
Kafka工作流程分析
Kafka的架构和数据的存储、生产、消费的流程。
Kafka的总体架构名词解释:
Producer:生产者,即消息发送者,push 消息到 Kafka 集群中的 broker(就是 server)中;
Broker:Kafka 集群由多个 Kafka 实例(server) 组成,每个实例构成一个 broker,说白了就是服务器;
Topic:producer 向 kafka 集群 push 的消息会被归于某一类别,即Topic,这本质上只是一个逻辑概念,面向的对象是 producer 和 consumer,producer 只需要关注将消息 push 到哪一个 Topic 中,而 consumer 只需要关心自己订阅了哪个 Topic;
Partition:每一个 Topic 又被分为多个 Partitions,即物理分区;出于负载均衡的考虑,同一个 Topic 的 Partitions 分别存储于 Kafka 集群的多个 broker 上;而为了提高可靠性,这些 Partitions 可以由 Kafka 机制中的 replicas 来设置备份的数量;如上面的框架图所示,每个 ...
Kafka基础
Kafka是由 Apache 软件基金会开发的一个开源流处理平台, 是一个分布式的基于发布/订阅模式的消息队列(Message Queue),支持多分区、多副本,主要应用于大数据实时处理领域。
Kafa基础架构图copyFromJvaaKeeper
Producer :消息生产者,就是向 kafka broker 发消息的客户端;
Consumer :消息消费者,向 kafka broker 取消息的客户端;
Consumer Group (CG):消费者组,由多个 consumer 组成。消费者组内每个消费者负责消费不同分区的数据,一个分区只能由一个组内消费者消费;消费者组之间互不影响。所有的消费者都属于某个消费者组,即消费者组是逻辑上的一个订阅者。
Broker :一台 kafka 服务器就是一个 broker。一个集群由多个 broker 组成。一个 broker 可以容纳多个 topic;
Topic :可以理解为一个队列,Kafka 的消息通过 Topics(主题) 进行分类,生产者和消费者面向的都是一个 topic;
Partition:为了实现扩展性,一个非常大的 ...