- 博客(427)
- 收藏
- 关注
原创 java排序算法
class Solution { void sort(int[] arr) { boolean remain = false; for (int i = 0; i < arr.length; i++) { for (int j = 0; j < arr.length - i - 1; j++) { if (arr[j] < arr[j + 1]) { ..
2021-06-05 01:18:42
79
原创 varchar、int与char的区别
char的特点char表示定长字符串,长度是固定的; 如果插入数据的长度小于char的固定长度时,则用空格填充; 因为长度固定,所以存取速度要比varchar快很多,甚至能快50%,但正因为其长度固定,所以会占据多余的空间,是空间换时间的做法; 对于char来说,最多能存放的字符个数为255,和编码无关varchar的特点varchar表示可变长字符串,长度是可变的; 插入的数据是多长,就按照多长来存储; varchar在存取方面与char相反,它存取慢,因为长度不固定,但正因如此,不占
2021-06-04 20:51:31
5080
原创 mysql中 in 和 exists 区别
mysql中的in语句是把外表和内表作hash 连接,而exists语句是对外表作loop循环,每次loop循环再对内表进行查询。一直大家都认为exists比in语句的效率要高,这种说法其实是不准确的。这个是要区分环境的。如果查询的两个表大小相当,那么用in和exists差别不大。 如果两个表中一个较小,一个是大表,则子查询表大的用exists,子查询表小的用in。 not in 和not exists:如果查询语句使用了not in,那么内外表都进行全表扫描,没有用到索引;而not extsts.
2021-06-04 20:50:29
120
原创 说出一些数据库优化方面的经验?
1、有外键约束的话会影响增删改的性能,如果应用程序可以保证数据库的完整性那就去除外键2、Sql语句全部大写,特别是列名大写.因为数据库的机制是这样的.sql语句发送到数据库服务器,数据库首先就会把sql编译成大写再执行,如果一开始就编译成大写就不需要了把Sql编译成大写这个步骤了。3、如果应用程序可以保证数据库的完整性.可以不需要按照三大范式来设计数据库4、其实可以不必要创建很多索引护索引可以加快查询速度,但是索引会消耗磁盘空间5、如果是jdbc的话,使用Preparedstateme...
2021-06-04 20:47:24
753
1
原创 Zookeeper的一致性保证
事务操作ZAB协议对于事务操作的处理是一个类似于二阶段提交过程。针对客户端的事务请求,leader服务器会为其生成对应的事务proposal,并将其发送给集群中所有follower机器,然后收集各自的选票,最后进行事务提交。流程如下图。ZAB协议的二阶段提交过程中,移除了中断逻辑(事务回滚),所有follower服务器要么正常反馈leader提出的事务proposal,要么就抛弃leader服务器。follower收到proposal后的处理很简单,将该proposal写入到事务日志,然后.
2021-06-04 19:19:49
291
1
转载 kafka 的 mmap文件读写方式
众所周知,kafka之所以吞吐量高,其中的一个重要原因就是因为其consumer在读取日志文件时使用了mmap的方式,mmap与常规文件读写的区别如下:总结:mmap之所以能有效提高kafka的吞吐量,是因为其在进行log文件读取的时候直接将log文件读入用户态进行缓存,绕过了内核态的page cache,避免了内核态和用户态的切换过程。参考:https://juejin.im/post/59f8691b51882534af254317#heading-16https://www.cnblogs
2021-06-01 19:42:22
550
原创 Kafka的哪些场景中使用了零拷贝(ZeroCOpy)?
在Kafka中,体现ZeroCopy使用场景的地方有两处:基于mmap的索引和日志文件读写所用的TransportLayer。mmap的索引 索引都是基于MappedByteBuffer的,也就是让用户态和内核态共享内核态的数据缓冲区,此时,数据不需要复制到用户态空间。不过,mmap虽然避免了不必要的拷贝,但是不一定就能保证很高的性能,在不同的操作系统下,mmap的创建和销毁成本可能是不一样的。很高的创建和销毁开销会抵消ZeroCopy带来的性能优势。由于这种不确定性,在Kafk...
2021-06-01 19:31:46
1261
1
原创 Java 对象的创建过程
1.实例变量初始化与实例代码块初始化我们在定义(声明)实例变量的同时,还可以直接对实例变量进行赋值或者使用实例代码块对其进行赋值。如果我们以这两种方式为实例变量进行初始化,那么它们将在构造函数执行之前完成这些初始化操作。实际上,如果我们对实例变量直接赋值或者使用实例代码块赋值,那么编译器会将其中的代码放到类的构造函数中去,并且这些代码会被放在对超类构造函数的调用语句之后(还记得吗?Java要求构造函数的第一条语句必须是超类构造函数的调用语句),构造函数本身的代码之前。...
2021-05-31 21:01:40
137
原创 java对象实例化顺序
静态成员变量 静态代码块 成员变量 方法块 构造函数 的加载顺序Java程序在执行过程中,类,对象以及它们成员加载、初始化的顺序如下:1、首先加载要创建对象的类及其直接与间接父类。2、在类被加载的同时会将静态成员进行加载,主要包括静态成员变量的初始化,静态语句块的执行,在加载时按代码的先后顺序进行。3、需要的类加载完成后,开始创建对象,首先会加载非静态的成员,主要包括非静态成员变量的初始化,非静态语句块的执行,在加载时按代码的先后顺序进行。4、最后执行构造器,构造器执行完毕,对象生成。...
2021-05-29 16:50:28
214
原创 java的volatile机制
由于CPU执行速度很快,而从内存读取数据和向内存写入数据的过程跟CPU执行指令的速度比起来要慢的多,因此如果任何时候对数据的操作都要通过和内存的交互来进行,会大大降低指令执行的速度。因此在CPU里面就有了高速缓存。当程序在运行过程中,会将运算需要的数据从主存复制一份到CPU的高速缓存当中,那么CPU进行计算时就可以直接从它的高速缓存读取数据和向其中写入数据,当运算结束之后,再将高速缓存中的数据刷新到主存当中。这样子当两个线程同时对一个变量修改,如i++,可能就会出现缓存不一致的问题。缓存一致性协议:
2021-05-28 19:59:04
102
原创 Java中Math.round(-1.5)
Math.round(-1.5)的返回值是-1。四舍五入的原理是在参数上加0.5然后做向下取整。System.out.println(Math.round(-1.5)); //-1System.out.println(Math.round(-1.6)); //-2
2021-05-27 15:50:25
183
原创 Java中equals和==的区别
java当中的数据类型和“==”的含义:基本数据类型(也称原始数据类型) :byte,short,char,int,long,float,double,boolean。他们之间的比较,应用双等号(==),比较的是他们的值。 引用数据类型:当他们用(==)进行比较的时候,比较的是他们在内存中的存放地址(确切的说,是堆内存地址)。注:对于第二种类型,除非是同一个new出来的对象,他们的比较后的结果为true,否则比较后结果为false。因为每new一次,都会重新开辟堆内存空间。equals().
2021-05-27 15:11:13
89
原创 G1垃圾回收器
G1回收器和CMS比起来,有以下不同:G1垃圾回收器是compacting的,因此其回收得到的空间是连续的。这避免了CMS回收器因为不连续空间所造成的问题。如需要更大的堆空间,更多的floating garbage。连续空间意味着G1垃圾回收器可以不必采用空闲链表的内存分配方式,而可以直接采用bump-the-pointer的方式; G1回收器的内存与CMS回收器要求的内存模型有极大的不同。G1将内存划分一个个固定大小的region,每个region可以是年轻代、老年代的一个。内存的回收是以regio
2021-05-26 21:38:29
434
原创 JVM 内存区域
程序计数器(PC,Program Counter Register)。在 JVM 规范中,每个线程都有它自己的程序计数器,并且任何时间一个线程都只有一个方法在执行,也就是所谓的当前方法。程序计数器会存储当前线程正在执行的 Java 方法的 JVM 指令地址;或者,如果是在执行本地方法,则是未指定值(undefined)。Java 虚拟机栈(Java Virtual Machine Stack),早期也叫 Java 栈。每个线程在创建时都会创建一个虚拟机栈,其内部保存一个个的栈帧(Stack Frame)
2021-05-26 19:56:32
67
原创 线程概念
Java 的线程是不允许启动(start)两次的,第二次调用必然会抛出 IllegalThreadStateException,这是一种运行时异常,多次调用 start 被认为是编程错误。关于线程生命周期的不同状态,在 Java 5 以后,线程状态被明确定义在其公共内部枚举类型 java.lang.Thread.State 中,分别是:新建(NEW),表示线程被创建出来还没真正启动的状态,可以认为它是个 Java 内部状态。 就绪(RUNNABLE),表示该线程已经在 JVM 中执行,..
2021-05-25 21:35:55
78
原创 synchronized和ReentrantLock
线程安全是一个多线程环境下正确性的概念,也就是保证多线程环境下共享的、可修改的状态的正确性,这里的状态反映在程序中其实可以看作是数据。线程安全需要保证几个基本特性:原子性,简单说就是相关操作不会中途被其他线程干扰,一般通过同步机制实现。 可见性,是一个线程修改了某个共享变量,其状态能够立即被其他线程知晓,通常被解释为将线程本地状态反映到主内存上,volatile 就是负责保证可见性的。 有序性,是保证线程内串行语义,避免指令重排等。.ReentrantLock可重入锁表示当一个线程试.
2021-05-25 19:46:48
119
原创 接口和抽象类
接口是对行为的抽象,它是抽象方法的集合,利用接口可以达到 API 定义和实现分离的目的。接口,不能实例化;不能包含任何非常量成员,任何 field 都是隐含着 public static final 的意义;同时,没有非静态方法实现,也就是说要么是抽象方法,要么是静态方法。抽象类是不能实例化的类,用 abstract 关键字修饰 class,其目的主要是代码重用。除了不能实例化,形式上和一般的 Java 类并没有太大区别,可以有一个或者多个抽象方法,也可以没有抽象方法。抽象类大多用于抽取相关 Java
2021-05-25 16:00:50
85
原创 IO方式
用户态空间(User Space)和内核态空间(Kernel Space),这是操作系统层面的基本概念,操作系统内核、硬件驱动等运行在内核态空间,具有相对高的特权;而用户态空间,则是给普通应用和服务使用。 当我们使用输入输出流进行读写时,实际上是进行了多次上下文切换,比如应用读取数据时,先在内核态将数据从磁盘读取到内核缓存,再切换到用户态将数据从内核缓存读取到用户缓存。基于 NIO transferTo 的实现方式,在 Linux 和 Unix 上,则会使用到零...
2021-05-25 11:29:54
233
原创 Java的IO操作
首先看两个概念区分同步或异步(synchronous/asynchronous)。同步是一种可靠的有序运行机制,当我们进行同步操作时,后续的任务是等待当前调用返回,才会进行下一步;而异步则相反,其他任务不需要等待当前调用返回,通常依靠事件、回调等机制来实现任务间次序关系。 区分阻塞与非阻塞(blocking/non-blocking)。在进行阻塞操作时,当前线程会处于阻塞状态,无法从事其他任务,只有当条件就绪才能继续,比如 ServerSocket 新连接建立完毕,或数据读取、写入操作完成;而非阻塞则
2021-05-24 22:48:49
149
2
原创 ConcurrentHashMap分析
早期 ConcurrentHashMap,其实现是基于:分离锁,也就是将内部进行分段(Segment),里面则是 HashEntry 的数组,和 HashMap 类似,哈希相同的条目也是以链表形式存放。 HashEntry 内部使用 volatile 的 value 字段来保证可见性,也利用了不可变对象的机制以改进利用 Unsafe 提供的底层能力,比如 volatile access,去直接完成部分操作,以最优化性能,毕竟 Unsafe 中的很多操作都是 JVM intrinsic 优化过的。在进
2021-05-24 22:22:25
338
1
原创 Hashtable、HashMap、TreeMap
Hashtable 是早期 Java 类库提供的一个哈希表实现,本身是同步的,不支持 null 键和值,由于同步导致的性能开销,所以已经很少被推荐使用。 HashMap 是应用更加广泛的哈希表实现,行为上大致上与 HashTable 一致,主要区别在于 HashMap 不是同步的,支持 null 键和值等。通常情况下,HashMap 进行 put 或者 get 操作,可以达到常数时间的性能。 TreeMap 则是基于红黑树的一种提供顺序访问的 Map,和 HashMap 不同,它的 get、put、re
2021-05-24 21:43:33
276
原创 Vector、ArrayList、LinkedList的区别与集合遍历
Vector 是 Java 早期提供的线程安全的动态数组,如果不需要线程安全,并不建议选择,毕竟同步是有额外开销的。Vector 内部是使用对象数组来保存数据,可以根据需要自动的增加容量,当数组已满时,会创建新的数组,并拷贝原有数组数据。ArrayList 是应用更加广泛的动态数组实现,它本身不是线程安全的,所以性能要好很多。与 Vector 近似,ArrayList 也是可以根据需要调整容量,不过两者的调整逻辑有所区别,Vector 在扩容时会提高 1 倍,而 ArrayList 则是增加...
2021-05-24 20:56:38
96
原创 String、StringBuffer、StringBuilder有什么区别
String是典型的 Immutable 类,被声明成为 final class,所有属性也都是 final 的。也由于它的不可变性,类似拼接、裁剪字符串等动作,都会产生新的 String 对象。StringBuffer 是为解决上面提到拼接产生太多中间对象的问题而提供的一个类,可以用 append 或者 add 方法,把字符串添加到已有序列的末尾或者指定位置。StringBuffer 本质是一个线程安全的可修改字符序列,它保证了线程安全,也随之带来了额外的性能开销,StringBuilder 是和
2021-05-24 20:10:32
105
原创 强引用、软引用、弱引用、幻象引用
强引用(“Strong” Reference),普通对象引用,只要还有强引用指向一个对象,就能表明对象还“活着”,垃圾收集器不会碰这种对象。对于一个普通的对象,如果没有其他的引用关系,只要超过了引用的作用域或者显式地将相应(强)引用赋值为 null,就是可以被垃圾收集的了,当然具体回收时机还是要看垃圾收集策略。 软引用(SoftReference),是一种相对强引用弱化一些的引用,可以让对象豁免一些垃圾收集,只有当 JVM 认为内存不足时,才会去试图回收软引用指向的对象。JVM 会确保在抛出 OutOfM
2021-05-24 19:40:03
101
原创 final、finally、 finalize
final 可以用来修饰类、方法、变量,分别有不同的意义,final 修饰的 class 代表不可以继承扩展,final 的变量是不可以修改的,而 final 的方法也是不可以重写的(override)。 finally 则是 Java 保证重点代码一定要被执行的一种机制。我们可以使用 try-finally 或者 try-catch-finally 来进行类似关闭 JDBC 连接、保证 unlock 锁等动作。 finalize 是基础类 java.lang.Object 的一个方法,它的设计目的是保
2021-05-24 19:20:20
96
原创 Exception和Error
Exception 和 Error 都是继承了 Throwable 类,在 Java 中只有 Throwable 类型的实例才可以被抛出(throw)或者捕获(catch)。Error 是指在正常情况下,不大可能出现的情况,绝大部分的 Error 都会导致程序(比如 JVM 自身)处于非正常的、不可恢复状态。既然是非正常情况,所以不便于也不需要捕获,常见的比如 OutOfMemoryError 之类,都是 Error 的子类。Exception 又分为可检查(checked)异常和不检查(unche
2021-05-24 17:08:52
149
原创 自动装箱与自动拆箱
自动装箱与自动拆箱Java 语言拥有 8 个基本类型,每个基本类型都有对应的包装(wrapper)类型。之所以需要包装类型,是因为许多 Java 核心类库的 API 都是面向对象的。举个例子,Java 核心类库中的容器类,就只支持引用类型。自动装箱对于基本类型的数值来说,我们需要先将其转换为对应的包装类,再存入容器之中。在 Java 程序中,这个转换可以是显式,也可以是隐式的,后者正是 Java 中的自动装箱。public int foo() { ArrayList<Int.
2021-05-24 00:05:27
73
原创 Java虚拟机实现synchronized
在 Java 程序中,我们可以利用 synchronized 关键字来对程序进行加锁。它既可以用来声明一个 synchronized 代码块,也可以直接标记静态方法或者实例方法。当声明 synchronized 代码块时,编译而成的字节码将包含 monitorenter 和 monitorexit 指令。这两种指令均会消耗操作数栈上的一个引用类型的元素(也就是 synchronized 关键字括号里的引用),作为所要加锁解锁的锁对象。关于 monitorenter 和 monitorexit 的作用
2021-05-23 12:01:29
84
原创 java垃圾回收
引用计数法与可达性分析引用计数法(reference counting)。为每个对象添加一个引用计数器,用来统计指向该对象的引用个数。一旦某个对象的引用计数器为 0,则说明该对象已经死亡,便可以被回收了。法处理循环引用对象。目前 Java 虚拟机的主流垃圾回收器采取的是可达性分析算法,这个算法的实质在于将一系列 GC Roots 作为初始的存活对象合集(live set),然后从该合集出发,探索所有能够被该集合引用到的对象,并将其加入到该集合中,这个过程我们也称之为标记(mark)。GC root可
2021-05-22 22:09:37
122
1
原创 Java对象的内存布局
每个 Java 对象都有一个对象头(object header),这个由标记字段和类型指针所构成。其中,标记字段用以存储 Java 虚拟机有关该对象的运行数据,如哈希码、GC 信息以及锁信息,而类型指针则指向该对象的类。在 64 位的 Java 虚拟机中,对象头的标记字段占 64 位,而类型指针又占了 64 位。也就是说,每一个 Java 对象在内存中的额外开销就是 16 个字节。以 Integer 类为例,它仅有一个 int 类型的私有字段,占 4 个字节。因此,每一个 Integer 对象的额外内存
2021-05-22 17:47:22
129
1
原创 反射调用的实现
反射主要是指程序可以访问、检测和修改它本身状态或行为的一种能力。Java的反射机制,操作的就是这个.class文件,首先加载相应类的字节码(运行eclipse的时候,.class文件的字节码会加载到内存中),随后解剖(反射 reflect)出字节码中的构造函数、方法以及变量(字段),或者说是取出。方法的反射调用,也就是 Method.invoke,实现如下:public class Test { public static void target(int i) { new Ex...
2021-05-22 16:29:32
795
原创 java异常机制
在 Java 语言规范中,所有异常都是 Throwable 类或者其子类的实例。Throwable 有两大直接子类。第一个是 Error,涵盖程序不应捕获的异常。当程序触发 Error 时,它的执行状态已经无法恢复,需要中止线程甚至是中止虚拟机。 第二子类则是 Exception,涵盖程序可能需要捕获并且处理的异常。Exception 有一个特殊的子类 RuntimeException,用来表示“程序虽然无法继续执行,但是还能抢救一下”的情况。前边提到的数组索引越界便是其中的一种。Runti
2021-05-22 15:34:41
399
原创 JVM执行方法调用
重载在 Java 程序里,如果同一个类中出现多个名字相同,并且参数类型相同的方法,那么它无法通过编译。在同一个类中定义名字相同的方法,那么它们的参数类型必须不同。重载的方法在编译过程中即可完成识别。具体到每一个方法调用,Java 编译器会根据所传入参数的声明类型(注意与实际类型区分)来选取重载方法。选取的过程共分为三个阶段:在不考虑对基本类型自动装拆箱(auto-boxing,auto-unboxing),以及可变长参数的情况下选取重载方法; 如果在第 1 个阶段中没有找到适配的方法,那么在允
2021-05-21 22:06:28
122
原创 Java类的加载、链接、初始化
Java 语言的类型可以分为两大类:基本类型(primitive types)和引用类型(reference types),基本类型是由Java 虚拟机预先定义好的。引用类型,Java 将其细分为四种:类、接口、数组类和泛型参数。由于泛型参数会在编译过程中被擦除(我会在专栏的第二部分详细介绍),因此 Java 虚拟机实际上只有前三种。在类、接口和数组类中,数组类是由 Java 虚拟机直接生成的,其他两种则有对应的字节流(如class文件)。加载启动类加载器负责加载最为基础、最为重要的类,比如存放在
2021-05-21 11:28:28
560
原创 1. Two Sum
Given an array of integers numsand an integer target, return indices of the two numbers such that they add up to target.You may assume that each input would have exactly one solution, and you may not use the same element twice.You can return the answe.
2021-05-20 21:01:37
77
原创 数据倾斜
数据量倾斜:在某些情况下,实例上的数据分布不均衡,某个实例上的数据特别多。bigkey 导致倾斜某个实例上正好保存了 bigkey。bigkey 的 value 值很大(String 类型),或者是 bigkey 保存了大量集合元素(集合类型),会导致这个实例的数据量增加,内存资源消耗也相应增加。把 bigkey 拆分成很多个小的集合类型数据,分散保存在不同的实例上。Slot 分配不均衡导致倾斜导致某个或某些实例上有大量数据。Hash Tag 导致倾斜Hash Tag 是指加在键
2021-05-20 19:39:10
115
原创 Redis的ACID属性
Redis 如何实现事务Redis 提供了 MULTI、EXEC 两个命令实现事务,MULTI开始一个事务,EXEC是实际执行事务,中间是业务逻辑。Redis 的事务机制能保证哪些属性原子性:一个事务中的多个操作必须都完成,或者都不完成。有以下三种情况:1. 在执行 EXEC 命令前,客户端发送的操作命令本身就有错误这种情况,在命令进入队列的时候,就可以判断出来,等到执行EXEC命令的时候,redis会拒绝所有提交的命令操作。2. 事务操作入队时,命令和操作的数据类型不匹配,但
2021-05-19 11:38:44
185
原创 影响redis性能的因素
主要影响redis性能的三个要素如下:redis自身操作特性、操作系统、文件系统。redis自身操作特性1. 慢指令查询 比如当Value 类型为 Set 时,SORT、SUNION/SMEMBERS 操作复杂度分别为 O(N+M*log(M)) 和 O(N)。复杂度增加了很多。处理方式:用其他高效命令代替。比如说,如果你需要返回一个 SET 中的所有成员时,不要使用SMEMBERS 命令,而是要使用 SSCAN 多次迭代返回,避免一次返回大量数据,造成线程阻塞。当你需...
2021-05-17 21:39:05
787
原创 CPU与redis性能
CPU的架构一个 CPU 处理器中一般有多个物理核,每个物理核都可以运行应用程序。每个物理核都拥有私有的一级缓存,它包括一级指令缓存和一级数据缓存,以及私有的二级缓存。L1和L2是私有的, 所以访问基本在纳秒级。但是L1和L2空间并不大,所以还有一个各个物理核共享的三级缓存L3。另外,每个物理核通常都会运行两个超线程,也叫作逻辑核。同一个物理核的逻辑核会共享使用 L1、L2 缓存。在主流的服务器上,一个 CPU 处理器会有多个物理核。同时,服务器上通常还会有多个 CPU 处理器(也称为多 CPU
2021-05-17 00:29:29
418
原创 Redis 实例的阻塞点
客户端阻塞点1. 复杂度高的增删改查操作例如集合元素全量查询操作 HGETALL、SMEMBERS,以及集合的聚合统计操作,例如求交、并和差集2. 删除大量键值对删除操作是要释放键值对占用的内存空间。为了更加高效地管理内存空间,在应用程序释放内存时,操作系统需要把释放掉的内存块插入一个空闲内存块的链表,以便后续进行管理和再分配。这个过程本身需要一定时间,而且会阻塞当前释放内存的应用程序,所以,如果一下子释放了大量内存,空闲内存块链表操作时间就会增加,相应地就会造成 Redis 主线程的阻塞。
2021-05-16 16:32:30
165
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人
RSS订阅