什么事情都有开始,人生中第一篇博客。梳理知识,再接再厉
1、设计一个黑白名单工具类,尽可能存储多ip
请实现一个IP白名单过滤算法,实现以下接口
boolean addWhiteIpAddress(String ip);
boolean isWhiteIpAddress(String ip);
要求如下:
占用空间尽量少
运算效率尽量高
在内存中完成查询及判断
接口可能被并发询问
尽量能存储整个IP地址空间
代码可运行,且包含单测
2、子类实现了finalize的方法,理解finalize只执行一次
/**
public void isAlive() {
System.out.println(“yes,i am still alive”);
}
@Override
protected void finalize() throws Throwable {
// super.finalize();
System.out.println(“finalize methode executed”);
instance = this;
}
public static void main(String[] args) throws InterruptedException {
instance = new FinalizeEscapeGC();
instance = null;
System.gc();
Thread.sleep(1000);
instance.isAlive(); //在没有重写finalize方法时,肯定是会报nullpointerException的
instance = null;
System.gc();
Thread.sleep(1000);
if (instance == null) {
System.out.println("i am dead;");
} else {
System.out.println("i am still live ;");
}
}
}
3、如何实现接口的冥等,有哪些解决方案?
算法题目,合并2个list,要求时间复杂度为2n.
public class Demo {
public static List
for (int i = 0; i < len1; i++) {
Map tmpMap = List1.get(i);
map.put(tmpMap.get(filedName).toString(), tmpMap);
}
for (int i = 0; i < len2; i++) {
Map tmp = List2.get(i);
if (map.containsKey(tmp.get(filedName))) {
Map map1 = map.get(tmp.get(filedName));
map1.putAll(tmp);
}
}
return List1;
}
}
4、实现一一个使用读写锁实现的缓存,用在写少读多的场景,考察锁升级和降级
Implement a cache class (CachedData) that caches the target data, and implement a method (processCachedData), which process the data if the cache is valid, if not, first update the cache object according to its data source, then process it.
Requirments:
Use ReentrantReadWriteLock to implement above requirements.
Use lock downgrading
锁降级和升级
lock实现机制
package com.demos;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class CachedData {
private static Map
private ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();//构造读写锁
public Object processCachedData(String key) {
Object value = null;
try {
rwl.readLock().lock();//当线程开始读时,首先开始加上读锁
value = cacheData.get(key);//获取值
if (value == null) {//判断是否存在值
try {
rwl.readLock().unlock();//在开始写之前,首先要释放读锁,否则写锁无法拿到
rwl.writeLock().lock();//获取写锁开始写数据
/* 再次判断该值是否为空,因为如果两个写线程如果都阻塞在这里,当一个线程
* 被唤醒后value的值不为null,当另外一个线程也被唤醒如果不判断就会执行两次写
*/
if (value == null) {
value = “queryDB”;
cacheData.put(key, value);
}
rwl.readLock().lock();//写完之后重入降级为读锁
} finally {
rwl.writeLock().unlock();//最后释放写锁
}
}
} finally {
rwl.readLock().unlock();//释放读锁
}
return value;
}
}
参考知识点:
也就是说,在另一个线程(假设叫线程1)修改数据的那一个瞬间,当前线程(线程2)是不知道数据此时已经变化了,但是并不意味着之后线程2使用的数据就是旧的数据,相反线程2使用还是被线程1更新之后的数据。也就是说,就算我不使用锁降级,程序的运行结果也是正确的(这是因为锁的机制和volatile关键字相似)。
那么为什么还要锁降级呢,其实目的是为了减少线程的阻塞唤醒。明显当不使用锁降级,线程2修改数据时,线程1自然要被阻塞,而使用锁降级时则不会。“感知”其实是想强调读的实时连续性,但是却容易让人误导为强调数据操作。
首先你没理解读写锁的意义,读锁的存在意味着不允许其他写操作的存在。
按照你提供的例子,可能存在一个事务线程不希望自己的操作被别的线程中断,而这个事务操作可能分成多部分操作更新不同的数据(或表)甚至非常耗时。如果长时间用写锁独占,显然对于某些高响应的应用是不允许的,所以在完成部分写操作后,退而使用读锁降级,来允许响应其他进程的读操作。只有当全部事务完成后才真正释放锁。
按你的理解如果当中写锁被其他线程占用,那么这个事务线程将不得不中断等待别的写锁释放。
所以总结下锁降级的意义应该就是:在一边读一边写的情况下提高性能。
5、手写一个队列,主要考察数组和锁机制,乐观锁和悲观锁都可以使用
Implement a Queue of your own design with an array or stack respectively, including push, pop, peek, empty methods.
synchronized
volatile
pop
peek
package com.demos;
public class StackDemo {
private Object[] array;
private volatile int topIndex = -1;
public StackDemo(int length) {
array = new Object[length];
}
public synchronized void push(Object obj) {
if (topIndex == (array.length - 1)) {
System.out.println("Stack is full ");
return;
}
array[++topIndex] = obj;
}
public synchronized Object peek() {
if (topIndex == -1) {
System.out.println("Stack is empty ");
return null;
}else{
return array[array.length - 1];
}
}
public synchronized Object pop() {
if (topIndex == -1) {
System.out.println("Stack is empty ");
return null;
}
Object topObject = array[topIndex];
array[topIndex] = null;
topIndex–;
return topObject;
}
public synchronized boolean empty() {
int size = array.length;
for (int i = 0; i < size; i++) {
array[i] = null;
}
return true;
}
}
6、
static final 分别修饰变量和类变量的区别
设计一个字符串转换器—springboot转换器 convertor,统一转换,比如日期戳转成日期格式
设计一个用户行为分析轨迹,比如某个用户操作了哪些菜单
如何做用户行为路径分析?前端埋点,后端行为日志
设计一个错误登录次数
设计登录鉴权系统
springmvc原理
7、
数据库索引前置规则:
多列索引情况下,按照前面的索引顺序组合
事务异常回滚机制,可配置哪些异常回归
Spring 事务的回滚机制主要采用异常回滚,如果某个方法不需要回滚就采用try catch机制捕获异常
另外一种方式是配置相关的异常,不让回滚
8、
JVM怎样判断两个类是否相同,对比Class对象
考察:对比2个Class,需要了解java类加载机制,不同的加载器加载相同的类,在JVM中呈现的Class对象是不同的,所以2个类比较除了权限名要一致以外,还需要是同一个类加载器加载
类加载和热加载机制
redis实现数据备份的机制,redis如何实现分布式锁
redis实现数据持久化的2中机制:
1.类似数据库中的写日志
2.快照方式
线程启动的方式和区别
1、通过start机制启动;
2、通过线程池启动
区别是线程池直接使用while调用队列中的task,然后直接调用run方法运行
volatile作用
内存可见,就是每次线程自己的缓存中的数据读取都取主存中读取。
linux docker机制
docker实现机制
k8s基本组件
synchronized和cAS区别
二分归并算法
双向链表编程实现排序插入
常用的设计模式:
创建型模式
单例 双重锁实现方式
简单工厂
抽象工厂
组合模式:
行为模式
代理
动态代理
适配器模式
责任链模式
门面模式
装饰器模式
嵌套类和内部类的访问范围报考
抽象类和接口的区别,是否可以包括private
动态加载类的方式
实现一个采集系统架构图,hash一致性算法实现负载均衡
包括:网关,采集服务,发送命令服务,鉴权,负载均衡
实现负载均衡有哪些算法?
kafka的高可用设计方式,topic partion
k8s高可用实现方式