1.用过哪些设计模式
详情见Java基础问题(四)
2.通信协议
TCP/IP,socket,报文,mqtt,…
3.分布式锁
为了保证一个方法或属性在高并发情况下的同一时间只能被同一个线程执行,在传统单体应用情况下,可以使用Java并发处理相关的API(如ReentrantLock或Synchronized)进行互斥控制,由于分布式系统多线程、多进程并且分布在不同机器上,这将使原单机部署情况下的并发控制锁策略失效,为了解决这个问题就需要一种跨JVM的互斥机制来控制共享资源的访问,这就是分布式锁要解决的问题!
具备条件
1、在分布式系统环境下,一个方法在同一时间只能被一个机器的一个线程执行;
2、高可用的获取锁与释放锁;
3、高性能的获取锁与释放锁;
4、具备可重入特性;
5、具备锁失效机制,防止死锁;
6、具备非阻塞锁特性,即没有获取到锁将直接返回获取锁失败。
实现的三种方式
基于数据库实现分布式锁;
基于缓存(Redis等)实现分布式锁;
基于Zookeeper实现分布式锁;
4.线程池
线程池设置
//设置核心线程数
executor.setCorePoolSize(5);
// 设置最大线程数
executor.setMaxPoolSize(20);
//配置队列大小
executor.setQueueCapacity(Integer.MAX_VALUE);
// 设置线程活跃时间(秒)
executor.setKeepAliveSeconds(60);
// 设置默认线程名称
executor.setThreadNamePrefix("我的线程名称");
// 等待所有任务结束后再关闭线程池
executor.setWaitForTasksToCompleteOnShutdown(true);
//执行初始化
executor.initialize();
5.一段复杂的逻辑业务怎么处理,使用什么模式比较好
1>(ps:这里最优解好像是模板模式)
模板模式:
创建一个抽象模板类:
public abstract class Game {
abstract void initialize();
abstract void startPlay();
abstract void endPlay();
//模板
public final void play(){
//初始化游戏
initialize();
//开始游戏
startPlay();
//结束游戏
endPlay();
}
}
创建不同的子类,每个子类继承模板类,重写模板方法,实现不同的逻辑。
最后去调用方法时,使用哪个子类逻辑,就去创建哪个的对象。他会进行顺序执行。
2>但是我感觉多方法工厂模式也可以,最后排列复杂逻辑业务顺序就行。
最后集中到一个总线上顺序执行(ps: 多方法工厂+单例模式?)。
6.用过哪些锁
1>互斥锁
一次只能一个线程拥有互斥锁,其他线程只有等待。互斥锁是在抢锁失败的情况下主动放弃CPU进入睡眠状态直到锁的状态改变时再唤醒,互斥锁在加锁操作时涉及上下文的切换。
2>自旋锁
在任何时刻同样只能有一个线程访问对象。但是当获取锁操作失败时,不会进入睡眠,而是会在原地自旋,直到锁被释放。这样节省了线程从睡眠状态到被唤醒期间的消耗,在加锁时间短暂的环境下会极大的提高效率。但如果加锁时间过长,则会非常浪费CPU资源
3>读写锁
读写锁是特殊的自旋锁。特性是读共享,写互斥,默认是读优先,但是改成了写优先(即上写锁失败时,会拒绝后续所有的读锁)。
4>悲观锁
顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。
5>乐观锁
顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。乐观锁适用于多读的应用类型,这样可以提高吞吐量,像数据库如果提供类似于write_condition机制的其实都是提供的乐观锁。
6>信号量
是用于线程间同步和互斥的,当一个线程完成操作后就通过信号量通知其它线程,然后别的线程就可以继续进行某些操作了。
7.redis高可用
两种方式
主从复制(Replication-Sentinel模式)
Redis集群(Redis-Cluster模式)
结语:
有些坑不得不踩,有些事不得不做,希望能通过分享互相进步,走过这段平凡的路。