java中的数据类型:
八种基本数据类型:byte、short、int、long、float、double、char、boolean;分为三类:数值型、字符型、布尔型。
存储原理:直接存储在内存中的内存栈上,数据本身的值就是存储在栈空间里面。
引用数据类型:类、接口、数组、枚举、注解
存储原理:创建的对象保存在堆中,对象的引用(指向堆中的地址)保存在存储在栈中。
注意:String属于引用数据类型,String是一个类,String在不通过new创建对象时,数据保存在常量池中。
String虽然是引用数据类型,但是相同的字符串在常量池中只存在一个,因此使用==比较是内容相同的字符串返回true。
Java位运算符(易忽略的运算符):
两个操作数:
1、&:按位取与,对应二进制位都为1时才为1。
例:9&3=1001&0011=0001=1
2、|:按位或,只要有1个为1就是1
3、^:按位异或,相同时为0
一个操作数:
4、~:按位取反,将二进制取反
5、<<:按位左移,高位舍弃,低位补0
6、>>:按位右移,低位舍弃,正数高位补0,负数补1
7、>>>:无符号右移,无论正负高位都补0
native关键字:
声明在方法上,表示这个方法是C/C++语言实现的,并且被编译成了DLL,由java调用
final关键字:
修饰类:不能被继承
修饰方法:不能被覆盖、重写
修饰属性:属性值不能被修改
Object中的常用方法:
getClass():用于获取对象的 class对象
hashCode():返回对象的哈希码
clone():用于对象的克隆(浅拷贝)
toString():但会类的名字
natify():唤醒一个在此对象监视器上等待的线程(使用wait方法等待的线程),如果有多个则唤醒任意一个
natifyAll():唤醒在此对象监视器上所有等待的线程
wait():暂停线程的执行,释放锁(sleep没有释放锁)
finalize():实例被垃圾回收器回收时触发的操作
集合框架:
List和Set继承自Collection接口,Map为独立接口
- Set(唯一):
HashSet,LinkedHashSet(有序,继承自HashSet,增加链表,实现了有序),TreeSet(有序、红黑树)
- List(可重复、有序)
ArrayList(数组),Vector(线程安全,底层是数组),LinkedList(双向链表)
- Map:
Hashtable(线程安全,数组+链表)
LinkedHashMap(继承自HashMap,增加了双向链表,因此有序),HashMap,TreeMap(红黑树)
Java多线程:
线程安全: 多个线程访问同一个对象时,如果不用考虑这些线程在运行时环境下的调度和交替执行,也不需要进行额外的同步,或者在调用方进行任何其他操作,调用这个对象的行为都可以获得正确的结果,那么这个对象就是线程安全的。
锁:
悲观锁:每次拿数据的时候都会上锁,适用于多写的场景
数据库中:表锁、行锁、读锁、写锁
java中:synchronized、ReentrantLock
乐观锁:拿数据的时候不会上锁,更新时会判断一下则期间别人有没有更新这个数据,可以使用版本号机制和CAS算法实现,适用于多读的应用场景
乐观锁实现方式:
版本号机制:
在数据库中增加版本号字段,进行数据操作时先读取版本号,提交更新的数据时匹配数据库中的版本是否与之前读取到的一致,一致则进行数据更新操作,然后将版本加一,不一致将被驳回。
CAS算法:
CAS(比较与交换),是一种无锁算法,即在没有现成被阻塞的情况下实现同步。
操作数:
需要读写的内存值:V
进行比较的值:A
拟写入的值:B
当且仅当V=A时,CAS通过原子方式用新值更新V的值(比较交换是一种原子操作)。
原子操作:不可中断的一个或者一系列操作,运行期间不会有任何的上下文交换
synchronized关键字
应用场景:
双重检查锁实现懒汉式的对象单例;
锁升级过程:(jdk1.6之前都是重量级锁)
1、无锁状态
2、偏向锁(默认开启):在对象头和栈帧中记录threadID,线程比较theadID来获取锁,不一致并且threadID线程还存活就会升级成轻量级锁
3、轻量级锁:自旋+CAS方式获取锁
4、重量级锁:自旋时间过长升级重量级锁,阻塞其他正在竞争该锁的进程。
注意:锁可以升级但不可以降级,但是偏向锁可以重置为无锁状态。
线程池:
线程池的好处:
降低资源消耗、提高响应速度、提高线程的可管理性
创建线程池:推荐使用ThreadPoolExecutor
线程池的七个参数:
必须的参数:
1、corePoolSize:核心线程数。默认情况下回一直存活
2、maximumPoolsize:线程池容纳的最大线程数
3、keepAliveTime:非核心线程闲置回收时间
4、unit:keepAliveTime时间的单位
5、workQueue:任务队列,通过线程池的 execute() 方法提交的 Runnable 对象将存储在该参数中。其采用阻塞队列实现。
可选的参数:
6、threadFactory(可选):线程工厂。用于指定为线程池创建新线程的方式。
7、handler(可选):拒绝策略。当达到最大线程数时需要执行的饱和策略。
线程池的常用方法:
execute():提交不需要返回值的任务
submit(runnable):提交带有返回值的任务,返回一个future对象,可以用来判断线程是否执行成功
executorService.shutdown():等到任务执行完毕后关闭线程池
executorService.shutdownNow():立即关闭线程池,不等待任务完成。
线程安全的特性:
1、原子性
2、可见性
3、有序性
synchronized保证原子性和可见性
volatile保证可见性和有序性,不能保证原子性
MySQL数据库
索引:
数据结构:hash、B+
hash:只支持快速的精确查找,但是不支持范围查找,范围查找会进行全盘扫描,适用于Redis这种KV情况的中间件
B+:是B树的升级版,B+树将飞叶子节点中的数据冗余一份到叶子节点中,然后把所有的叶子节点形成一个链连在一起,提高了范围查找的效率。
聚簇索引:
默认主键索引是聚簇索引,表的顺序是按照聚簇索引的顺序排列的,一个表只能有一个聚簇索引,查询时先在辅助索引上查找对应的id值,然后根据id在主键索引上查找,因此需要二次查找。查询效率高。
非聚簇索引:
索引是独立的,通过辅助键检索无需访问主键的索引树。
表记录数过大时优化措施:
1、限定数据范围:查询时一定加限定条件
2、读写分离(分库):主库负责写,从库负责读
3、垂直分区(分表):将一个表的不同列进行拆分,查询时使用join查询
4、水平分区(分表):表结构不变,将数据分片,将每一片数据放进不同的表或者库中
事务的特性:
1、原子性:事务不可分割,要么全部完成,要么全部不完成。
2、一致性:事务的执行的前后数据的完整性保持一致.
3、隔离性:多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。
4、持久性:事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。
事务在多线程下的问题:
脏读:读取到的数据是别的事务已经修改但还未提交的数据
丢失修改:两个事务同时修改数据,导致其中一个事务修改丢失
不可重复读(修改):一个事务读取两次数据,两次结果不一致,中间别修改了
幻读(新增或删除):事务A读取到几行数据,另一个事务B插入或删除一些行,事务A发现前后数据不一致
Redis:
高性能:Redis中的数据存储在内存中,操作缓存就是直接操作内存,速度相当快,能承受的请求数远远大于直接操作数据库能承受的请求数。
为什么不用map?
redis是分布式缓存,map是本地缓存,每个实例都要拥有一份自己的缓存,缓存不具有一致性。
与memcached区别:
memcached不支持久化,多线程,只有string和二进制类型
常用的数据结构:
String类型:KV形式
Hash类型:K:k1,v1,k2,v2
适合存储对象
List类型:(列表有序)K,v1,v2,v3...
Set类型:(无序)K,v1,s1,v2,s2,v3,s3...s:分数,能用来排序
Sorted Set类型:(有序集合)
持久化机制:
快照持久化(RDB):默认的持久化方式,将Redis某个时间点上的数据副本保存。
设置方式:save 时间(秒) 发生变化的个数
追加文件持久化(AOF):每执行一条更改Redis中数据的命令,就会将该命令写入硬盘中的AOP文件appendonly.aof
设置方式:appendonly yes
Spring:
AOP(面向切面):基于动态代理,利用AOP实现方法的增强,可进行日志的记录和一些事物处理等。
动态代理:
1、JDK:实现了被代理对象的接口,只能对实现类接口的类生成代理,通过反射机制调用
2、Cglib:实质上是继承了被代理对象,覆盖了其中的方法,无法实现被final修饰的方法或类,通过
IOC(控制反转):控制反转就是将我们的bean对象交给spring容器来管理,而不是通过new的方式,实现了程序间的松耦合。