简单,八个字: 临时存储+ 定时任务。 Broker收到延时消息了,会先发送到主题(SCHEDULE_TOPIC_XXXX)的相应时间段的Message Queue中,然后通过一个定时任务轮询这些队列,到期后,把消息投递到目标Topic的队列中,然后消费者就可以正常消费这些消息。
NameServer因为是无状态,且不相互通信的,所以只要集群部署就可以保证高可用。RocketMQ的高可用主要是在体现在Broker的读和写的高可用,Broker的高可用是通过集群和主从实现的。Broker可以配置两种角色:Master和Slave,Master角色的Broker支持读和写,Slave角色的Broker只支持读,Master会向Slave同步消息。 也就是说Producer只能向
简单来说,RocketMQ是一个分布式消息队列,也就是消息队列+ 分布式系统。 作为消息队列,它是发- 存- 收的一个模型,对应的就是Producer、Broker、 Cosumer;作为分布式系统,它要有服务端、客户端、注册中心,对应的就是 Broker、Producer/Consumer、NameServer 所以我们看一下它主要的工作流程:RocketMQ由NameServer注册中心集群、
RocketMQ提供了两种刷盘策略:同步刷盘和异步刷盘 同步刷盘:在消息达到Broker的内存之后,必须刷到commitLog日志文件中才成功,然后返回Producer数据已经发送成功。 异步刷盘:异步刷盘是指消息达到Broker内存后就返回Producer数据已经发送成功,会唤醒一个线程去将数据持久化到CommitLog日志文件中。 Broker 在消息的存取时直接操作的是内存(内存映射文件),
Producer端在发送消息的时候,会先根据Topic找到指定的TopicPublishInfo,在获取了TopicPublishInfo路由信息后,RocketMQ的客户端在默认方式下selectOneMessageQueue()方法会从TopicPublishInfo中的messageQueueList中选择一个队列(MessageQueue)进行发送消息。具这里有一个sendLatencyF
按照垃圾收集,将Java堆划分为新生代 (Young Generation)和老年代(Old Generation)两个区域。新生代存放存活时间短的对象,而每次回收后存活的少量对象,将会逐步晋升到老年代中存放。 而新生代又可以分为三个区域,eden、from、to,比例是8:1:1,而新生代的内存分区同样是从垃圾收集的角度来分配的。
如果对象在进行可达性分析后发现没有与GC Roots相连接的引用链,那它将会被第一次标记,随后进行一次筛选,筛选的条件是此对象是否有必要执行finalize()方法。如果对象在在finalize()中成功拯救自己——只要重新与引用链上的任何一个对象建立关联即可,譬如把自己 (this关键字)赋值给某个类变量或者对象的成员变量,那在第二次标记时它就”逃过一劫“。但是如果没有抓住这个机会,那么对象就真
弱引用弱引用也是用来描述那些非必须对象,但是它的强度比软引用更弱一些,被弱引用关联的对象只能生存到下一次垃圾收集发生为止。当垃圾收集器开始工作,无论当前内存是否足够,都会回收掉只被弱引用关联的对象。在JDK 1.2版之后提供了WeakReference类来实现弱引用。Object obj = new Object(); ReferenceQueue queue = new ReferenceQue
Java中的引用有四种,分为强引用(Strongly Reference)、软引用(Soft Reference)、弱引用(Weak Reference)和虚引用(Phantom Reference)4种,这4种引用强度依次逐渐减弱。 强引用是最传统的引用的定义,是指在程序代码之中普遍存在的引用赋值,无论任何情况下,只要强引用关系还存在,垃圾收集器就永远不会回收掉被引用的对象。Object obj
可以作为GC Roots的主要有四种对象:虚拟机栈(栈帧中的本地变量表)中引用的对象 方法区中类静态属性引用的对象 方法区中常量引用的对象 本地方法栈中JNI引用的对象对象有哪几种引用?Java中的引用有四种,分为强引用(Strongly Reference)、软引用(Soft Reference)、弱引用(Weak Reference)和虚引用(Phantom Reference)4种,这4种引
有两种方式,引用计数算法(reference counting)和可达性分析算法。 引用计数算法引用计数器的算法是这样的:在对象中添加一个引用计数器,每当有一个地方引用它时,计数器值就加一;当引用失效时,计数器值就减一;任何时刻计数器为零的 对象就是不可能再被使用的。可达性分析算法目前 Java 虚拟机的主流垃圾回收器采取的是可达性分析算法。这个算法的实质在于将一系列 GC Roots 作为初始的
内存泄漏可能的原因有很多种:静态集合类引起内存泄漏静态集合的生命周期和 JVM 一致,所以静态集合引用的对象不能被释放。public class OOM { static List list = new ArrayList(); public void oomTests(){ Object obj = new Object(); list.add(obj); } }单例模式和上面的例子原理类似,单
在JVM的几个内存区域中,除了程序计数器外,其他几个运行时区域都有发生内存溢出(OOM)异常的可能,重点关注堆和栈。Java堆溢出Java堆用于储存对象实例,只要不断创建不可被回收的对象,比如静态对象,那么随着对象数量的增加,总容量触及最大堆的容量限制后就会产生内存溢出异常(OutOfMemoryError)。 这就相当于一个房子里,不断堆积不能被收走的杂物,那么房子很快就会被堆满了。public
内存泄露就是申请的内存空间没有被正确释放,导致内存被白白占用。 内存溢出就是申请的内存超过了可用内存,内存不够了。 两者关系:内存泄露可能会导致内存溢出。 用一个有味道的比喻,内存溢出就是排队去蹲坑,发现没坑位了,内存泄漏,就是有人占着茅坑不拉屎,占着茅坑不拉屎的多了可能会导致坑位不够用。
Java程序会通过栈上的reference数据来操作堆上的具体对象。由于reference类型在 《Java虚拟机规范》里面只规定了它是一个指向对象的引用,并没有定义这个引用应该通过什么方式去定位、访问到堆中对象的具体位置,所以对象访问方式也是由虚拟机实现而定的,主流的访问方式主要有使用句柄和直接指针两种: 如果使用句柄访问的话,Java堆中将可能会划分出一块内存来作为句柄池,reference中
在HotSpot虚拟机里,对象在堆内存中的存储布局可以划分为三个部分:对象头(Header)、实例数据(Instance Data)和对齐填充(Padding)。对象头对象头主要由两部分组成:第一部分:存储对象自身的运行时数据:哈希码、GC分代年龄、锁标志状态、线程持有的锁、偏向线程ID、偏向时间戳等,官方称它为Mark Word,它是个动态的结构,随着对象状态变化。第二部分:第二部分是类型指针,
会。假设JVM虚拟机上,每一次new对象时,指针就会向右移动一个对象size的距离,一个线程正在给A对象分配内存,指针还没来得及修改,另一个为对象B分配内存的线程又引用了这个指针来分配内存,这就发生了抢占。有两种方案来解决这个问题:1、CAS采用CAS分配重试的方式来保证更新操作的原子性2、TLAB每个线程在Java堆中预先分配一小块内存,也就是本地线程分配缓冲(Thread Local Allo
内存分配有两种方式,指针碰撞(Bump The Pointer)、空闲列表(Free List)。指针碰撞:假设Java堆中内存是绝对规整的,所有被使用过的内存都被放在一 边,空闲的内存被放在另一边,中间放着一个指针作为分界点的指示器,那所分配内存就仅仅是把那个指针向空闲空间方向挪动一段与对象大小相等的距离,这种分配方式称为“指针碰撞”。 空闲列表:如果Java堆中的内存并不是规整的,已被使用的内
在JVM中对象的创建,我们从一个new指令开始:首先检查这个指令的参数是否能在常量池中定位到一个类的符号引用;检查这个符号引用代表的类是否已经被加载、解析和初始化过。如果没有,就先执行相应的类加载过程;类加载检查通过后,接下来虚拟机将为新生对象分配内存;内存分配完成后,虚拟机将分配到的空间(但不包括对象头)都初始化为零值;接下来设置对象头,请求头里包含了对象是哪个类的实例、如何才能找到类的元数据信
Java虚拟机规范规定的方法区只是换种方式实现。有客观和主观两个原因。 客观上使用永久代来实现方法区的决定的设计导致了Java应用更容易遇到内存溢出的问题(永久代有-XX:MaxPermSize的上限,即使不设置也有默认大小,而J9和JRockit只要没有触碰到进程可用内存的上限,例如32位系统中的4GB限制,就不会出问题),而且有极少数方法 (例如String::intern())会因永久代的原
JDK1.6、1.7/1.8内存区域发生了变化,主要体现在方法区的实现: JDK1.6使用永久代实现方法区:DK1.7时发生了一些变化,将字符串常量池、静态变量,存放在堆上在JDK1.8时彻底干掉了永久代,而在直接内存中划出一块区域作为元空间,运 行时常量池、类常量池都移动到元空间。
JVM内存区域最粗略的划分可以分为堆和栈,当然,按照虚拟机规范,可以划分为以下几个区域:JVM内存分为线程私有区和线程共享区,其中方法区和堆是线程共享区, 虚拟机栈、本地方法栈和程序计数器是线程隔离的数据区。 1、程序计数器 程序计数器(Program Counter Register)也被称为PC寄存器,是一块较小的内存空间。 它可以看作是当前线程所执行的字节码的行号指示器。 2、Java虚拟机
JVM——Java虚拟机,它是Java实现平台无关性的基石。 Java程序运行的时候,编译器将Java文件编译成平台无关的Java字节码文件(.class),接下来对应平台JVM对字节码文件进行解释,翻译成对应平台匹配的机器指令并运行。同时JVM也是一个跨语言的平台,和语言无关,只和class的文件格式关联,任何语言,只要能翻译成符合规范的字节码文件,都能被JVM运行。
单机线程池执行断电了应该怎么处理?我们可以对正在处理和阻塞队列的任务做事务管理或者对阻塞队列中的任务持久化处理,并且当断电或者系统崩溃,操作无法继续下去的时候,可以通过回溯日志的方式来撤销正在处理的已经执行成功的操作。然后重新执行整个阻塞队列。 也就是说,对阻塞队列持久化;正在处理任务事务控制;断电之后正在处理任务的回滚,通过日志恢复该次操作;服务器重启后阻塞队列中的数据再加载。Fork/Join
我们自己的实现就是完成这个核心流程: 线程池中有N个工作线程 把任务提交给线程池运行 如果线程池已满,把任务放入队列 最后当有空闲时,获取队列中任务来执行实现代码:这样,一个实现了线程池主要流程的类就完成了。
线程池如何实现参数的动态修改线程池提供了几个 setter方法来设置线程池的参数。这里主要有两个思路:1、在微服务架构下,可以利用配置中心,如Nacos、Apollo等等,也可以自己开发配置中心。业务服务读取线程池配置,获取相应的线程池实例来修改线程池的参数。2、如果限制了配置中心的使用,也可以自己去扩展ThreadPoolExecutor,重写方法,监听线程池参数变化,来动态修改线程池参数。线程
线程池异常怎么处理在使用线程池处理任务的时候,任务代码可能抛出RuntimeException,抛出异常后,线程池可能捕获它,也可能创建一个新的线程来代替异常的线程,我们可能无法感知任务出现了异常,因此我们需要考虑线程池异常情况。 常见的异常处理方式:线程池有几种状态线程池有这几个状态:RUNNING,SHUTDOWN,STOP,TIDYING,TERMINATED。//线程池状态 private
newFixedThreadPool (固定数目线程的线程池) newCachedThreadPool (可缓存线程的线程池) newSingleThreadExecutor (单线程的线程池) newScheduledThreadPool (定时及周期执行的线程池)前三种线程池的构造直接调用ThreadPoolExecutor的构造方法。newSingleThreadExecutorpublic
一、线程池的线程数应该怎么配置?线程在Java中属于稀缺资源,线程池不是越大越好也不是越小越好。任务分为计算密集型、IO密集型、混合型。 1. 计算密集型:大部分都在用CPU跟内存,加密,逻辑操作业务处理等。 2. IO密集型:数据库链接,网络通讯传输等。一般的经验,不同类型线程池的参数配置:1、计算密集型一般推荐线程池不要过大,一般是CPU数+1,+1是因为可能存在页缺失(就是可能存在有些数据在
一、线程池提交execute和submit有什么区别?1. execute 用于提交不需要返回值的任务threadsPool.execute(new Runnable() { @Override public void run() { // TODO Auto-generated method stub } });2. submit()方法用于提交需要返回值的任务。线程池会返回一个futu
Copyright © 2005-2025 51CTO.COM 版权所有 京ICP证060544号