文章目录
一、Java基础
Java常见的运行时异常
ArithmeticException(算术异常)
ClassCastException (类转换异常)
IllegalArgumentException (非法参数异常)
IndexOutOfBoundsException (下标越界异常)
NullPointerException (空指针异常)
SecurityException (安全异常)
IOException(输入输出异常)
FileNotFoundException(文件未找到异常)
NumberFormatException(字符串转换为数字异常)
反射机制的优缺点
- 优点:可以在程序运行过程中,动态获取某个类的属性和方法,提高程序灵活性和扩展性。
- 缺点:
- 通过反射可以访问私有方法和私有属性,可能会破坏程序的封装性。
- 反射机制效率低,因为反射需要解析字节码文件,反射包含一些动态类型,JVM无法对代码进行优化,所以性能较低。
Map的几种类型
HashMap:最常用,访问速度快,遍历取数据顺序完全随机,根据HashCode存数据,根据键可以直接获取值,允许一条记录key为null,非线程安全的。
HashTable:不允许key为null,线程安全。
LinkedHashMap:保存了记录的插入顺序,按顺序遍历。
TreeMap:默认按键值升序排序,可以指定排序比较器,用迭代器遍历时,得到的记录是排序过的。
public class Test {
public static void main(String[] argv) {
Map<Integer, Integer> hashMap = new HashMap();
Map<Integer, Integer> treeMap = new TreeMap();
Map<Integer, Integer> linkedHashMap = new LinkedHashMap();
System.out.println("test HashMap:");
testMap(hashMap);
System.out.println("test TreeMap:");
testMap(treeMap);
System.out.println("test LinkedHashMap:");
testMap(linkedHashMap);
}
static void testMap(Map<Integer, Integer> map) {
map.put(4, 1);
map.put(3, 2);
map.put(2, 3);
map.put(1, 4);
for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
System.out.println(entry.getKey() + " : " + entry.getValue());
}
}
}
// 输出:
/*
test HashMap:
1 : 4
2 : 3
3 : 2
4 : 1
test TreeMap:
1 : 4
2 : 3
3 : 2
4 : 1
test LinkedHashMap:
4 : 1
3 : 2
2 : 3
1 : 4
*/
使用HashMap的时候,用String做key的好处
HashMap内部实现是通过key的hashcode来确定value的存储位置,因为字符串是不可变的,所以当创建字符串时,它的hashcode被缓存下来,不需要再次计算,所以相比于其他对象更快
二、Redis
Redis和MySQL数据一致性解决方案
延时双删策略:在写库前后都进行redis.del(key)操作,并且设定合理的超时时间。
public void write(String key,Object data){
redis.delKey(key);
db.updateData(data);
Thread.sleep(500);
redis.delKey(key);
}
- 具体的步骤就是:先删除缓存; 再写数据库; 休眠500毫秒(根据实际设置时间); 再次删除缓存。
- 最差的情况:在休眠时间内数据存在不一致,而且又增加了写请求的耗时。
异步更新缓存(基于订阅binlog的同步机制):
技术整体思路:MySQL binlog增量订阅消费 + 消息队列 + 增量数据更新到Redis
- 读Redis:热数据基本都在Redis
- 写MySQL:增删改都是操作MySQL
- 更新Redis数据:MySQL的数据操作binlog,来更新到Redis
Redis更新:
数据操作主要分为两大块:
- 一个是全量(将全部数据一次写入到redis)
- 一个是增量(实时更新):指的是MySQL的update、insert、delete变更数据。
读取binlog后分析 ,利用消息队列,推送更新各台的redis缓存数据。
- 这样一旦MySQL中产生了新的写入、更新、删除等操作,就可以把binlog相关的消息推送至Redis,Redis再根据binlog中的记录,对Redis进行更新。
- 消息推送工具你也可以采用别的第三方:kafka、rabbitMQ等来实现推送更新Redis。
三、JVM
双亲委派是为了解决什么问题
Java的双亲委派机制是为了解决Java类加载器的命名冲突和安全性问题。
- Java类加载器采用了一种层级结构,主要分为三个层次:启动类加载器、扩展类加载器和应用程序类加载器。每个类加载器都有一个父类加载器,父类加载器加载的类可以被子类加载器使用,而子类加载器加载的类不能被父类加载器使用,这样就可以避免命名冲突。
- 双亲委派机制指的是当一个类加载器需要加载一个类时,它首先会将这个任务委托给它的父类加载器去完成,如果父类加载器不能完成这个任务,子类加载器才会尝试加载这个类。这种委派机制可以保证Java类的安全性,因为父类加载器加载的类可以被子类加载器共享,而子类加载器不能加载父类加载器中的类,从而避免了恶意代码的潜在风险。
- 双亲委派机制还可以提高Java程序的性能,因为在加载一个类时,如果该类已经被父类加载器加载过了,那么子类加载器就不需要再加载一遍,直接使用父类加载器中已经加载好的类即可,从而提高了Java程序的效率。
垃圾回收算法
- 标记-清除(新生代):标记存活的对象,然后清除没有标记的对象。缺点:效率不高,无法清除垃圾碎片。
- 复制算法(新生代,默认):按照容量划分二个大小相等的内存区域,当一块用完的时候将活着的对象复制到另一块上,然后再把已使用的内存空间一次清理掉。缺点:内存使用率不高,只有原来的一半。
- 标记-整理算法(老年代):标记存活的对象,让所有存活的对象都向一端移动,然后直接清除掉端边界以外的内存。
Redis的内存淘汰策略
- no-envicition:不允许淘汰数据(默认)
- allkeys-random:所有的键中,随机淘汰
- allkeys-lru:所有的键中,淘汰最近最少使用
- allkeys-lfu:所有的键中,淘汰某段时间使用频次最小
- volatile-random:设置过期时间的key,随机淘汰
- volatile-lru:设置过过期时间的key,淘汰最近最少使用
- volatile-lfu:设置了过期时间的key,淘汰某段时间使用频次最小
- volatile-ttl:设置过期时间的key,淘汰即将过期的
Redis过期键的删除策略
- 立即删除:
- 惰性删除:客户端访问这个key的时候,redis对key的过期时间进行检查,如果过期了就立即删除,不会给你返回任何东西。
- 定时删除:
四、MySQL
主从架构
数据库主主:两台都是主数据库,同时对外提供读写操作。客户端可以访问任意一台。数据存在双向同步。
数据库主从:一台是主数据库,对外提供读写操作。一台是从数据库,对外提供读的操作。数据从主库同步到从库。
数据库主备:一台是主数据库,对外提供读写操作。一台是备库,只作为备份使用,不对外提供读写,一旦主机挂了它就取而代之。数据从主库同步到备库。