算法提升-1-哈希表与哈希函数
自定义结构 RandomPool
请设计出一种结构,在该结构中有如下三个功能,要求其时间复杂度为 $O(1)$
insert(key):将某个 key 加入到该结构,做到不重复加入
delete(key):将原本在结构中的某个 key 移除
getRandom(): 等概率随机返回结构中的任何一个key
设计思路
设计两个哈希表 keyIndexMap 和 indexKeyMap
keyIndexMap 用来记录 key 到 index 的对应关系
indexKeyMap 用来记录 index 到 key 的对应关系
整数size初始化为0,记录Pool的大小
执行 insert(newKey),将(newKey,size)放入keyIndexMap,将(size,newKey)放入indexKeyMap,然后size自增
执行 delete(deleteKey),最新加入的key记为lastKey,对应的index信息记为lastIndex。删除的key记为deleteKey,对应的index记为deleteKey
把记录(lastKey,last ...
JUC-4-LockSupport与线程中断
线程中断机制中断机制一个线程不应由其他线程来强制中断或停止,而应该由线程自己自行停止,因此Thread.stop/suspend/resume被废弃。Java提供了一种用于停止线程的协商机制—中断,它只是一种协作协商机制,Java没有给中断增加任何语法。若要中断一个线程,你需要手动调用该线程的interrupt方法,该方法也仅仅是将线程对象的中断标识设成true;接着需要自己写代码检测当前线程的标识位,如果为true,表示别的线程请求这条线程中断。每个线程对象中都有一个中断标识位,用于表示线程是否被中断,该标识位为true表示中断,为false表示未中断。该方法可以在别的线程中调用,也可以在自己的线程中调用。
中断API
方法
说明
public void interrupt()
实例方法,仅仅设置线程的中断状态为true,发起一个协商而不会立即停止一个线程
public static boolean interrupted()
静态方法,判断线程是否被中断并清除当前中断状态;1. 返回当前线程的中断状态,测试当前线程是否已被中断;2. 将当前线程的状态状态清零,并 ...
MySQL高级篇-7-InnoDB数据存储结构
数据库的存储结构—页索引结构给我们提供了高效的索引方式,不过索引信息以及数据记录都是保存在文件上的,确切说是存储在页结构中。另一方面,索引是在存储引擎中实现的,MySQL服务器上的存储引擎负责对表中数据的读取和写入工作。不同存储引擎中存放的格式一般是不同的,甚至有的存储引擎比如Memory都不用磁盘来存储数据。
磁盘与内存交互基本单位lnnoDB将数据划分为若干个页,InnoDB中页的大小默认为16KB以页作为磁盘和内存之间交互的基本单位,也就是一次最少从磁盘中读取16KB的内容到内存中,一次最少把内存中的16KB内容刷新到磁盘中
数据库管理存储空间的基本单位是页,数据库IO操作的最小单位是页。一个页中可以存储多个行记录。在数据库中,不论读一行,还是读多行,都是将这些行所在的页进行加载。
记录是按照行来存储的,但是数据库的读取并不以行为单位,否则一次读取(即一次IO操作)只能处理一行数据,效率比较低
页结构概述页a、页b、页c..页n这些页可以不在物理结构上相连,只要通过双向链表相关联即可。每个数据页中的记录会按照主键值从小到大的顺序组成一个单向链表,每个数据页都会为存储在它里边 ...
JVM 内存与垃圾回收篇-7-StringTable
String的基本特性
String:字符串,使用一对""引起来表示
12String s1 = "cyan"; // 字面量定义String s2 = new String("cyan")
String 声明为final的,不可被继承
String 实现了Serializable接口:表示字符串是支持序列化的
String 实现了Comparable接口:表示string可以比较大小
String 在jdk8及以前内部定义了final char[ ] value用于存储字符串数据。jdk9时改为byte[]
String:代表不可变的字符序列,即不可变性。
当对字符串重新赋值时,需要重写指定内存区域赋值,不能使用原有的value进行赋值
当对现有的字符串进行连接操作时,也需要重新指定内存区域赋值,不能使用原有的value进行赋值
当调用String的replace ()方法修改指定字符或字符串时,也需要重新指定内存区域赋值,不能使用原有的value进行赋值
通过字面量的方式(区别于new)给一个字符串赋值, ...
JUC-3-多线程锁
悲观锁与乐观锁
悲观锁
他认为自己在使用数据时一定有别的线程来修改数据,因此在获取数据时先加锁,确保数据被别的线程修改。常见的有synchronized关键字和Lock的实现类
应用场景:
适合写操作多的场景,先加锁可以保证写操作时数据正确,显式地锁定后再操作同步资源
乐观锁
他认为自己在使用数据时不会有别地线程修改数据或资源,所以不会添加锁。在Java中是通过使用无锁编程来实现,只是在更新数据时去判断之前有没有其他线程更新这个数据。如果该数据没有更新,当前线程将自己修改的数据成功写入;如果该数据已经被其他线程更新,则根据不同实现方式执行不同的操作
判断规则:
版本号机制(Version)
CAS算法(Java原子类中的递增操作采用CAS自旋实现)
应用场景:
适合读操作多的场景,不加锁的特点使其读操作的性能大幅提升。乐观锁则直接去操作同步资源,是一种无锁算法
案例演示
悲观锁
123public synchronized void m1() { // 加锁后的业务逻辑}
1234567891011// 保证多个线程使用的是同一个lock对象的前 ...
JVM 内存与垃圾回收篇-6-执行引擎
执行引擎概述
执行引擎是Java虚拟机核心的组成部分之一
“虚拟机”是一个相对于“物理机”的概念,这两种机器都有代码执行能力,其区别是物理机的执行引擎是直接建立在处理器、缓存、指令集和操作系统层面上的,而虚拟机的执行引擎则是由软件自行实现的,因此可以不受物理条件制约地定制指令集与执行引擎的结构体系,能够执行那些不被硬件直接支持的指令集格式。
JVM的主要任务是负责装载字节码到其内部,但字节码并不能够直接运行在操作系统上,因为字节码指令并非等价于本地机器指令,它内部包含的仅仅只是一些能够被JVM所识别的字节码指令、符号表,以及其他辅助信息
执行引擎(Execution Engine)的任务就是将字节码指令解释/编译为对应平台上的本地机器指令
从外观上来看,所有的Java虚拟机的执行引擎输入、输出都是一致的:输入的是字节码二进制流,处理过程是字节码解析执行的等效过程,输出的是执行结果。
执行引擎工作过程
执行引擎在执行的过程中究竟需要执行字节码指令完全依赖于PC寄存器
每当执行完一项指令操作后,PC寄存器就会更新下一条需要被执行的指令地址
当然方法在执行的过程中,执行 ...