上篇文章介绍了堆外内存DirectByteBuffer,我们知道了DirectByteBuffer是分配在JVM堆外的ByteBuffer,这篇文章来了解堆内内存HeapByteBuffer。HeapByteBufferHeapByteBuffer,即分配在JVM中的heap堆中的ByteBuffer,调用ByteBuffer#allocate()即可生成一个HeapByteBuffer对象。publicstaticByteBufferallocate(intcapacity){if(capacity<0)thrownewIllegalArgumentException();return
前面9篇文章我们已经深入了解了NIO的基本概念和核心原理,想必小伙伴们对NIO的三大组件已经了然于心了,对于ByteBuffer而言,其实还有两个较为特殊的类DirectByteBuffer和MappedByteBuffer没有分析,这两个类的原理都是基于内存文件映射的。ByteBuffer分为两种,一种是直接的,另外一种是间接的。直接缓冲:直接使用内存映射,对于Java而言就是直接在JVM之外分配虚拟内存地址空间,Java中使用DirectByteBuffer来实现,也就是堆外内存。间接缓冲:是在JVM堆上实现,Java中使用HeapByteBuffer来实现,也就是堆内内存。我们这篇文章主
多线程架构前面所有文章的示例服务端都是单线程模式,这种模式存在很多的缺陷无法充分利用多核CPU的性能如果服务端某个读写操作耗时较多,则会拖慢整个服务端所以,这篇文章大明哥将介绍服务端多线程的模式,让我们榨干服务器性能。我们清楚服务端主要做两件事,建立连接和处理读写事件,所以我们可以将服务端的线程分为两组:一个线程专门处理accept事件,我们称之为Boss线程CPU核心数个线程,这些线程处理读写事件,我们称之为Worker线程这个时候,客户端服务端的关系如下:Boss线程只服务处理Acept事件,Worker线程只处理读写事件,他们都各自维护一个Selector,每个Selector负责监听自
背景我们先看下面一段代码。publicstaticvoidmain(String[]args)throwsException{ServerSocketChannelserverSocketChannel=ServerSocketChannel.open();serverSocketChannel.configureBlocking(false);serverSocketChannel.bind(newInetSocketAddress(8081));Selectorselector=Selector.open();serverSocketChannel.register(selector,Se
整理完成后再补充内容
上篇文章(Netty入门—第一个完整的demo之智能客服)大明哥演示了强大的智能客服,它能够很好的解决用户的一些常见的问题,但是有些问题依然还需要人工客服来完成,所以这篇文章我们来实现人工坐席。功能实现当用户输入0的时候,智能客户需要将这个用户转发给某一个人工客服,如果没有人工客户在线需要提示用户是否继续等待。在等待期间若有人工客服上线则将其转接到该用户。那么服务端需要做如下几件事情:维护用户与人工坐席之间的关系,发的消息不能串。将人工坐席分配给用户。若没有人工坐席,则在用户等待期间,人工坐席上线则将其转接给该用户。消息的转发。至于用户和人工坐席,则相对来说就比较简单了,接收服务端的消息,并发
在前面8篇文章中,大明哥详细阐述了Netty核心组件的基本原理及核心API的使用,但是那些只是API的使用,且只有一个简单的helloworld的demo,没有一个demo来完整演示客户端与服务端之间的交互。这篇文章就完整演示客户端与服务端的交互,场景:智障客户(zzkf)。如果有小伙伴对Netty的核心组件还不是很清晰的话,可以移步相关文章再复习下:Netty入门—要想掌握Netty,你必须知道它的这些核心组件Netty入门—Bootstrap,一切从这里开始Netty入门—ByteBuf,Netty数据传输的载体Netty入门—Channel,把握Netty通信的命门Netty入门—Cha
Java接口我相信所有学过Java的人一定都知道,而且我也相信99%的人一定都背过这个面试题:Java接口和抽象类的区别是什么?答案都是什么接口方法不能有实现,都是抽象的,接口的方法都默认为public修饰等等之类的,这些在Java8之前是正确的,但是随着Java的发展,它不再是正确的了。这篇文章就跟着大明哥一起来探索Java接口的进化之路。出生:Java1.0引入接口Java1.0,作为Java语言的最初版本,于1996年发布。在这个版本中,Java引入了接口(Interface)这一概念,标志着面向对象编程(OOP)在Java中的深入应用。在Java1.0中,接口被定义为完全抽象的,它具备
上篇文章(【死磕NIO】—详解Selector)详细介绍了Selector的核心原理和使用方法,这篇文章我们来深入了解Selector的源码,主要讲三个最常用的方法open(),register()和selector()。open()调用Selector.open()方法会创建一个Selector实例。publicstaticSelectoropen()throwsIOException{returnSelectorProvider.provider().openSelector();}SelectorProvider是一个抽象类,它提供了创建Selector、ServerSocketChan
前面4篇文章深入分析了NIO三大组件中的两个:Buffer和Channel:【死磕NIO】—深入分析Buffer【死磕NIO】—深入分析Channel和FileChannel【死磕NIO】—跨进程文件锁:FileLock【死磕NIO】—探索SocketChannel的核心原理这篇文章则介绍第三个组件:Selector。相比Buffer和Channel而言,Selector对于NIO来说显得更加重要,因为它是NIO实现多路复用的核心,它的使命就是完成IO的多路复用。Selector简介在前一篇文章:【死磕NIO】—ServerSocketChannel的应用实例,大明哥分析了ServerSock
在上篇文章(Netty入门—ChannelHandler,Netty的数据加工厂)提到ChannelHandler虽然是一个好的打工人,但是在我们实际业务线中,他不可能一个人干所有的活啊,毕竟都21世纪了,我们是要讲究分工的。所以Netty就需要一个好的组织者将这些ChannelHandler组织起来,形成一个条完整,高效的业务线,这个组织者就是ChannelPipeline。ChannelPipeline概述pipeline翻译为管道、流水线,在Netty这个大工厂中,ChannelPipeline就像一条流水线,数据流过ChannelPipeline,被一步一步地加工,最后得到一个成熟的工
经过前面几篇文章的介绍,我们掌握了Netty的5个核心组件,但是有了这5个核心组件Netty这个工厂还是无法很好的运转,因为缺少了一个最核心的组件:EventLoop,它是Netty中最最核心的组件,也是Netty最精华的部分,它负责Netty中I/O事件的分发,也就是说,这个事件谁来做,它说了算。再谈Reactor线程模型要想弄明白Netty的EventLoop,我们就必须先理解Reactor线程模型,Netty高性能的奥秘就在于Reactor线程模型。线程模型的优劣直接决定了系统的性能,一个好的线程模型比不好的线程模型性能会高出好多倍。而目前主流的网络框架选择的线程模型几乎都是I/O多路复
我相信小伙伴一定看过多篇怎么去掉if...else的文章,也知道大家都很有心得,知道多种方法来去掉if...else,比如Option,策略模式等等,但我相信大明哥这篇文章绝对是最全,最完备怎么去掉if...else的文章,里面有些方法我相信有小伙伴肯定不知道,我也不卖关子,直接进入主题,如何干掉if...else。方法一:提前return假如有如下代码:if(condition){doSomething;}else{return;}这种代码我们一般采用提前return的方式,去掉不必要的else。if(!condition){return}doSomething;这种方法一般只适合分支结构很
在《阿里巴巴Java开发规范》手册最后一节的应用分层中推荐了应用系统的分层结构。我比较赞同这种分层结构,这种分层结构带来了诸多好处,但是有一个麻烦之处就是分层领域模型,也就是我们所说的各种O,比如DTO、POJO、DO、VO等等,这样就导致我们项目中存在各种属性相同的xxO,对于有些工作经验的小伙伴们来说知道使用BeanUtils来实现属性复制,但是对于工作经验不是很多的小伙伴可能就是各种set和get了。这是非常尴尬的一件事。Spring的BeanUtils虽然可以满足我们大部分的需要,但是只能赋值属性名相同且类型一致的两个属性,比如VO里面的beginTime是String类型的,而BO里
上篇文章(Netty入门—Bootstrap,一切从这里开始),我们了解了Netty的第一个核心组件:Bootstrap,它是Netty程序的开端。今天我们来熟悉Netty的第二个组件:ByteBuf,Netty数据传输的载体。在Netty中,数据的读写都是以ByteBuf为单位进行交互的。为什么要造轮子?在学习JavaNIO的时候,JavaNIO有一个原生的ByteBuffer,为什么Netty不直接使用原生的,要重复造一个呢?因为不好用啊。为什么不好用呢?因为JavaNIO的ByteBuffer有一些设计上的缺陷和痛点。我们先看ByteBuffer内部结构。JavaNIO的ByteBuff
上篇文章(Netty入门—要想掌握Netty,你必须知道它的这些核心组件)大明哥阐述了Netty的整体结构,从这篇文章开始大明哥就将这个整体进行拆分讲解,今天是第一个核心组件:Bootstrap。一句话来概括Bootstrap,无论是Netty的客户端还是服务端程序,都是从这里开始的。在Netty入门—亘古不变的HelloWorld一文的demo中,我们首先创建一个ServerBootstrap对象(服务端)或者Bootstrap对象(客户端),然后调用他们的各个方法进行组装整个Netty服务端和客户端,从代码中我们可以看出这两个类是一个辅助类,用来辅助服务端或者客户端初始化和启动的。Boot
在上篇文章(Netty入门—亘古不变的HelloWorld)中,我们简单认识了开发一个Netty服务端和客户端代码的主要步骤了,在这几大步骤中我们基本上可以看出Netty的几个核心组件。在真正进入Netty的学习之前,我们非常有必要先对这些组件进行一个整体的认识,对于Netty入门阶段的讲解,大明哥采用整体—>分解—>总结的模式来阐述。对于一头牛,我们需要先知道这是一头牛,了解这头牛有哪些组织,然后再把这些组织一个一个地拆开来认识,清楚里面每一个组织的功能,最后再将这些组织组合成一头牛,是不是就会清晰很多。Bootstrap:引导器Bootstrap的意思是引导,一个Netty应用
这篇文章我们正式开始学习Netty,在入门之前我们还是需要了解什么是Netty。什么是Netty为什么很多人都推崇Javaboy去研究Netty?Netty这么高大上,它到底是何方神圣?用官方的话说:Netty是一款异步的、基于事件驱动的网络应用程序框架,用以快速开发高性能、高可靠性的网络IO程序。为什么要使用Netty呢?因为使用原生的JavaNIO非常不爽,它存在一系列的问题,比如:使用JavaNIO需要了解很多概念,而且API非常繁琐。使用JavaNIO编程复杂,一不小心就会Bug横飞。开发工作量和难度也很大,例如我们要处理断开重连、网络闪断、半包读写、网络拥塞、异常处理,等等异常情况,
上一个死磕Java专栏【死磕NIO】(当然写的不是很好,争取今年将它重写一遍)是**【死磕Netty】**的铺垫,对于我们Java程序员而言,我们在实际开发过程一般都不会直接使用JavaNIO作为我们的网络编程框架,因为写出一套高质量的JavaNIO程序并不是一件容易的事,除了JavaNIO固有的复杂性和bug之外,作为NIO服务端,我们要处理的事情太多了,如网络闪断、客户端认证、消息编解码、半包读写,客户端一样也有很多复杂的事情要处理,所以如果我们对JavaNIO没有足够了解,没有足够的网络编程经验的话,利用JavaNIO来编写一个高性能的稳定网络编程框架并不是一件容易的事。所以我们一般都不
前面两篇文章介绍了Java原生序列化算法和Hessian,我们知道Java原生序列化算法有很多缺陷和不足支出,而Hessian也足够的优秀,但是它依然不是最牛逼的,这篇文章大明哥就带你们来了解一个更牛逼的序列化算法:Google出品的ProtoBuf。ProtoBuf是什么ProtoBuf(ProtocolBuffers)是Google推出的一个结构化数据交换协议,用于传递自定义的消息格式,可用于分布式应用之间的数据通信或者异构环境下的数据交换。ProtoBuf是一种语言无关、平台无关、高效、扩展性良好的语言,提供了一种将结构化数据进行序列化和反序列化的方法。它提供了多种语言的实现:Java、
在Java序列化之深入理解Java序列化和反序列化一文中,大明哥说到,Java的原生序列化存在三个缺点:无法跨语言序列化后的字节流太大序列化时间太长这三个缺陷是我们在开发过程中是无法容忍的,所以我们必须来寻找一个可替代的方案。Hessian就是一个不错的选择。什么是HessianHessian是一种动态类型、二进制序列化和Web服务协议,专为面向对象的传输而设计。与Java原生序列化类似,Hessian也是采用二进制协议,不过它比Java原生序列化的性能更加高,序列化的字节数也更小。与Java原生序列化相比,Hessian具有如下几个特点(http://hessian.caucho.com/d
先看代码:publicclassSingleton{privateSingleton(){}privatestaticclassSingletonInstance{privatestaticfinalSingletoninstance=newSingleton();}publicstaticSingletongetInstance(){returnSingletonInstance.instance;}}我想应该没有不知道这行个类是干嘛的小伙伴了吧,这是单例模式的一种写法。单例模式是每一个Javaer必须要掌握的设计模式,它所描述的是在某个进程内,某个类有且仅有一个实例。我们知道要破坏单例模式
基本概念Java序列化和反序列化三连问:什么是Java序列化和反序列化?为什么需要Java序列化和反序列化?如何实现Java序列化和反序列化?是什么一句话就能够说明白什么是Java序列化和反序列化?Java序列化是将Java对象转换为字节序列的过程,而Java反序列化则是将字节序列恢复为Java对象的过程。序列化:任何需要保存到磁盘或者在网络进行传输的Java对象都需要支持序列化,序列化后的字节流保存了Java对象的状态及相关的描述信息,反序列化能够根据这些信息“复刻”出一个一模一样的对象。序列化的核心作用就是对象状态的保存。反序列化:反序列化就是根据磁盘中保存的或者网络上传输的字节流中所保存
在前面几篇文章中,小编陆陆续续介绍了Redis用到的所有主要数据结构,如比如简单动态字符串(SDS)、字典(dict)、压缩列表(ziplist)、整数集合(intset)、跳跃表(skiplist)。然而Redis并没有直接使用这些数据结构来实现键值对的数据库,而是在这些数据结构之上又包装了一层RedisObject(对象),RedisObject有五种对象:字符串对象、列表对象、哈希对象、集合对象和有序集合对象。redisObject定义在redis.h文件中:typedefstructredisObject{unsignedtype:4;unsignedencoding:4;unsign
intset是Redis实现Set的底层实现之一,当集合元素不大于设定值并且元素都是整数时,就会用intset作为Set的底层数据结构。它有如下几个特点:元素类型只能为数字元素有三种类型:int16_t、int32_t、int64_t元素有序且不可重复和SDS一样,intset也是内存连续的,就像数组一样下面是数据结构的定义:typedefstructintset{//编码类型int16_t、int32_t、int64_tuint32_tencoding;//长度最大长度:2^32uint32_tlength;//数组,元素int8_tcontents[];}intset;encoding:为
关于跳跃表其实在JUC里面有一个并发容器就是利用跳跃表来实现的:ConcurrentSkipListMap(【死磕Java并发】—–J.U.C之Java并发容器:ConcurrentSkipListMap)。这篇博客我们来分析Redis里面的跳跃表。skiplist什么是跳跃表?百度百科是这么定义的:跳表是一个随机化的数据结构,实质就是一种可以进行二分查找的有序链表。跳表在原有的有序链表上面增加了多级索引,通过索引来实现快速查找。跳表不仅能提高搜索性能,同时也可以提高插入和删除操作的性能。从这里我们我们了解到,跳跃表是一种有序的数据结构,通过在节点上面增加索引(指针)从而达到快速检索的目的。跳
这篇文章我们来分析Redis数据结构的第三个:ziplist。什么是ziplist什么是ziplist?Redis官方是这样定义的:Theziplistisaspeciallyencodedduallylinkedlistthatisdesignedtobeverymemoryefficient.Itstoresbothstringsandintegervalues,whereintegersareencodedasactualintegersinsteadofaseriesofcharacters.Itallowspushandpopoperationsoneithersideoftheli
字符串使我们在编程过程中使用最为广泛的对象了,在Redis中同样如此。我们知道Redis是C语言实现的,但是Redis放弃了C语言传统的字符串而是自己创建了一种名为简单动态字符串SDS(SimpleDynamicString)的抽象类型,并将SDS用作Redis的默认字符串表示,其主要原因就是传统的字符串表示方式并不能满足Redis对字符串在安全性、效率、以及功能方面的要求。所以这篇文章就来说说SDS。在Redis里面,只会将C语言字符串当做字符串字面量,用于一些无须对字符串进行修改的地方,比如打印日志。在大多数场景下,Redis都是使用SDS来作为字符串的表示。对比C语言字符串,SDS具有如
字典,又称映射,是一种用于保存键值对的抽象数据结构。在Redis中,字典得到了广泛的使用,比如Redis的数据库就是使用字典来作为底层实现的Redis中的字典有dict.h/dict结构表示,如下:typedefstructdict{//类型特定函数//type里面主要记录了一系列的函数,可以说是规定了一系列的接口dictType*type;//私有数据//privdata保存了需要传递给那些类型特定函数的可选参数void*privdata;//两张哈希表dicththt[2];//rehash索引,并没有rehash时,值为-1longrehashidx;//目前正在运行的安全迭代器的数量u
Redis是一个可基于内存亦可持久化的日志型(aof,rdb)、高性能Key-Value数据库,并提供多种语言的API,Redis支持主从同步。数据可以从主服务器向任意数量的从服务器上同步,从服务器可以是关联其他从服务器的主服务器。本文将详细介绍Rediscluster搭建过程,集群为三主三从。准备工作本次集群准备三台服务器(虚拟机也可以),每台服务器上面安装两个Redis实例,端口分别是6379和6380,如下:IPRedis实例192.168.2.170Redis1(6379/主)、Redis2(6380/从)192.168.2.142Redis1(6379/主)、Redis2(6380/