(1)在设计模式的应用能力上,有了很大的提高,使用模板设计模式,架构实例反向同步到架构定义,使用了策略模式
(2)
答:
答:权威接线和初始的接线的状态的比较判断,刚开始一下子把所有的数据中心的数据都拉到本地内存中,发现有OOM问题,后面逐个同步单个数据中心的数据,同步的粒度缩小了,这样的话就能够同步完成了。
OOM分析之问题定位
答:有日志报错,通过OOM的报错信息(java.lang.OutOfMemoryError: Java heap space),我们知道是堆发生了OOM了,因为我们事先设置了-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/path_to_directory参数,配置了发生OOM时的内存快照转储路径,所以从这个指定的路径中查找到相应的OOM文件,再通过MAT工具发现了这里有一个列表特别大,所以我们分析就知道了这个代码问题出在了哪
答:jdbc原生接口支持几百张表的同步,避免创建大量的同步表;利用数据表进行隔离,多线程同时进行同步操作,加速同步过程;增量同步,在夜间进行同步操作
答:
(1)外部csv文件包含了需要需要同步的表的表名,每一行数据包含了表名、源库名、目的库名,服务一启动就会读取csv文件,然后将其放入到map当中
(2)主线程读取这个map中,然后遍历这个map,将这个map中的表名,源库名,目的苦命放入到创建的Runnable对象当中,这个runnable对象负责写具体的表级别的同步逻辑,然后再调用已经创建好的线程池对象的execute方法就可以执行这个任务了,这个任务后续是排队还是直接执行就看自己使用的哪个类型的线程池了。
答:通过ThreadPoolExecutor创建的,给这个里面传入了核心线程数,最大线程数,阻塞队列,保活时间以及自定义线程工厂
答:一一对象,一个线程处理一张表
答:当时想的是核心线程数设置为20,这是根据公式(核心线程数=cpu核数(线程等待时间/线程执行任务的平均时间+1)得来的,最大线程数设置表的数量,然后再使用一个阻塞队列,这里的非核心线程的数量也不敢设置的太大,因为数据同步涉及到大量的数据迁移任务,所以如果同步的过程中同时从mysql中拉取了太多的数据时,可能会造成OOM;
如果待同步的表数据量基本不大,而且后面做的是修改操作,则同步操作使用cachedThreadPool比较好。
因为这是一个IO密集型的需求,一个任务的IO时间很长,也就是说在网络IO期间会被阻塞,cpu空闲时间会很长,
对于IO密集型的任务,由于线程在等待IO(例如,磁盘操作或网络请求)时不会消耗CPU,可以使用较多的线程来提高系统的吞吐量。但是,线程本身不是免费的,因为它们需要内存(例如,线程栈)并增加了线程调度的开销。因此,线程数量也不能过多。
以下是针对IO密集型需求设计线程池的一些建议:
线程数设置:
CPU核数 * 2
或者更高。选择合适的队列:
ArrayBlockingQueue
,可以防止任务过多积压,导致内存溢出。线程的存活时间:
拒绝策略:
RejectedExecutionException
,但也可以选择其他策略,例如调用者运行策略,让提交任务的线程自己去执行这个任务。使用任务优先级:
监控与调优:
总之,对于IO密集型的需求,主要的目标是最大化系统的吞吐量。这通常意味着需要使用较多的线程,并合理配置线程池的各项参数。
答:核心线程可以在线程池被声明出来时就被创建,这样的话相当于是线程预热的作用,任务一来了就能用,这是通过preStart参数控制的
答:运行、就绪、阻塞、终止
Java中,一个线程的生命周期包括多个状态。下面是Java线程的主要状态:
新建(NEW):
start()
方法时,线程处于此状态。可运行(RUNNABLE):
start()
方法,但线程调度器还未选择它作为当前执行的线程时,它处于可运行状态。这也包括了线程正在Java虚拟机内部运行的状态。阻塞(BLOCKED):
等待(WAITING):
Object.wait()
Thread.join()
LockSupport.park()
超时等待(TIMED_WAITING):
Thread.sleep(long millis)
Object.wait(long timeout)
Thread.join(long millis)
LockSupport.parkNanos()
或 LockSupport.parkUntil()
终止(TERMINATED):
run()
方法完成或线程被中断时,线程处于此状态。在Java编程中,你可以使用 Thread.getState()
方法来获取一个线程的当前状态。这对于调试和线程管理是非常有用的。
答:如果说线程是阻塞态,它应该不怎么占用cpu,被挂起到了阻塞队列中,所以应该重点关注运行态的线程
答:
答:当一个应用的线程数持续缓慢增长,但访问量、CPU和负载都相对稳定时,可能的情况有:
线程泄露:有些线程可能没有被正确关闭,导致随着时间的推移,线程数量逐渐增加。这在使用自定义线程或线程池时可能会发生。
第三方库/组件:可能使用的某个库或组件在内部创建了线程,并且没有正确地管理它们。
为了进一步分析:
线程堆栈分析:可以使用Java的内置工具 jstack
来查看应用的线程堆栈。这将为每个线程提供一个快照,显示线程在做什么。通过这个工具,可以识别出不断增长的线程是做什么的,是由哪部分代码启动的。
关注状态:尤其是 WAITING 和 TIMED_WAITING 的线程。虽然这些线程可能不会消耗大量的CPU,但它们可能是因为等待某个资源或某个条件而被阻塞,导致线程数增长。
监视工具:使用如VisualVM, JProfiler等工具可以实时监控线程的创建、状态和销毁。这可以帮助识别线程创建的模式和可能的线程泄露。
日志审查:查看应用的日志,检查是否有异常、错误或其他相关信息,这可能与线程的行为有关。
代码审查:检查代码中所有创建线程或线程池的地方,确保线程在完成其任务后被正确关闭。
结论:当线程数持续增长但其他指标相对稳定时,很可能是线程管理问题或线程泄露。关键是找到哪些线程不断被创建并为什么它们没有被正确地关闭。
答:横向表示一个线程执行时花费的cpu时间,纵向表示方法的调用栈,因为你刚刚说的是线程不怎么占用cpu,即任务可能执行完了,但是没有被正确释放,所以火焰图是不适用于解决这个问题的
分析:可以参考lc162. 寻找峰值和lc33. 搜索旋转排序数组
int getMin(int[] a){
int l=1,r=a.length-2;
while(l<=r){
int m=(l+r)/2;
if(a[m-1]>a[m]&&a[m+1]>a[m])
return a[m];
if(a[m-1]>a[m]){
l=m+1;
} else if(a[m+1]>a[m]){
r=m-1;
}
}
return a[l];
}
答:两个月左右,最好马上过来,双方加深一下了解
答:还有一轮hr和面试一起跟你聊
答:hr可能会看
答:一个是消费医疗,主要阵地在淘宝和支付宝里面,另一个是线上线下的购药场景,近期可能有一些医疗大模型的语料的清洗和生产,你实习期间可能会在大模型这一块做,正式的话可能会根据个人意愿
答:北京和杭州都可以
答:你已经过了
答:对,然后hr也会做一些沟通