1 你的什么专业?在你的专业方向做了什么工作?,主要是在研究生做了哪些工作?做了哪些课题?
2 大数据的相关组件你了解吗?
hadoop 的原理 Flume的原理 ……一些大数据相关的组件的原理。
3 sleep()和wait的区别?
这两个方法来自不同的类分别是Thread和Object 。
最主要是sleep方法没有释放锁,而wait方法释放了锁,使得其他线程可以使用同步控制块或者方法(锁代码块和方法锁)。
wait,notify和notifyAll只能在同步控制方法或者同步控制块里面使用,而sleep可以在任何地方使用(使用范围) 。
sleep必须捕获异常,而wait,notify和notifyAll不需要捕获异常 。
4 Currenthashmap的的原理和底层实现
ConcurrentHashMap 和 HashMap 思路是差不多的,但是因为它支持并发操作,所以要复杂一些。整个 ConcurrentHashMap 由一个个 Segment 组成, Segment 代表”部分“或”一段“的意思,所以很多地方都会将其描述为分段锁。注意,行文中,我很多地方用了“槽”来代表一个segment。ConcurrentHashMap 是一个Segment数组Segment 通过继承ReentrantLock 来进行加锁,所以每次需要加锁的操作锁住的是一个segment,这样只要保证每个 Segment 是线程安全的,也就实现了全局的线程安全。JDk1.7的时候
JDK1.8在JDK1.8中,放弃了Segment臃肿的设计,取而代之的是采用Node + CAS + Synchronized来保证并发安全进行实现,synchronized只锁定当前链表或红黑二叉树的首节点,这样只要hash不冲突,就不会产生并发,效率又提升N倍。
5 Redis的持久化操作和原理以及实现操作
redis提供两种方式进行持久化,一种是RDB持久化(原理是将Reids在内存中的数据库记录定时 dump到磁盘上的RDB持久化),另外一种是AOF(append only file)持久化(原理是将Reids的操作日志以追加的方式写入文件)
RDB持久化是指在指定的时间间隔内将内存中的数据集快照写入磁盘,实际操作过程是fork一个子进程,先将数据集写入临时文件,写入成功后,再替换之前的文件,用二进制压缩存储
AOF持久化以日志的形式记录服务器所处理的每一个写、删除操作,查询操作不会记录,以文本的方式记录,可以打开文件看到详细的操作记录。
|
AOF |
RDB |
优点 |
1AOF 可以更好的保护数据不丢失,一般 AOF 会每隔 1 秒,通过一个后台线程执行一次fsync操作,最多丢失 1 秒钟的数据 2AOF 日志文件以 append-only 模式写入,所以没有任何磁盘寻址的开销,写入性能非常高,而且文件不容易破损,即使文件尾部破损,也很容易修复。 3AOF 日志文件即使过大的时候,出现后台重写操作,也不会影响客户端的读写. 4AOF 日志文件的命令通过非常可读的方式进行记录,这个特性非常适合做灾难性的误删除的紧急恢复。 |
1RDB 会生成多个数据文件,每个数据文件都代表了某一个时刻中 redis 的数据,这种多个数据文件的方式,非常适合做冷备,可以将这种完整的数据文件发送到一些远程的安全存储上去 2RDB 对 redis 对外提供的读写服务,影响非常小,可以让 redis 保持高性能 3相对于 AOF 持久化机制来说,直接基于 RDB 数据文件来重启和恢复 redis 进程,更加快速。 |
缺点 |
1对于同一份数据来说,AOF 日志文件通常比 RDB 数据快照文件更大 2AOF 开启后,支持的写 QPS 会比 RDB 支持的写 QPS 低AOF 这种较为复杂的基于命令日志 / merge / 回放的方式,比基于 RDB 每次持久化一份完整的数据快照文件的方式 |
1如果想要在 redis 故障时,尽可能少的丢失数据,那么 RDB 没有 AOF 好 2RDB 每次在 fork 子进程来执行 RDB 快照数据文件生成的时候,如果数据文件特别大,可能会导致对客户端提供的服务暂停数毫秒,或者甚至数秒。 |
6 对并发和并行的理解?
并发(concurrency)
指宏观上看起来两个程序在同时运行,比如说在单核cpu上的多任务。但是从微观上看两个程序的指令是交织着运行的,你的指令之间穿插着我的指令,我的指令之间穿插着你的,在单个周期内只运行了一个指令。这种并发并不能提高计算机的性能,只能提高效率
并行(parallelism)
指严格物理意义上的同时运行,比如多核cpu,两个程序分别运行在两个核上,两者之间互不影响,单个周期内每个程序都运行了自己的指令,也就是运行了两条指令。这样说来并行的确提高了计算机的效率。所以现在的cpu都是往多核方面发展。
简单理解
并发:一个处理器可以同时处理多个任务。这是逻辑上的同时发生。
并行:多个处理器同时处理多个不同的任务。这是物理上的同时发生。
7 数据库的表的相关的连接操作?
内连接:两个表格的的交集
外连接:两个表格数据的并集
左连接:左边表格的全部数据的连接右边的相匹配的数据
右连接:右边表格的全部数据的连接左边的相匹配的数据
8 Union 和union All的相关的区别?
UNION 并集,表中的所有数据,并且去除重复数据(工作中主要用到的是这个);
UNION ALL,表中的数据都罗列出来;
9 java里面cylicbarrier和countdownlunch,区别?是如何使用的?实现代码?
DK 的并发包中提供了几个非常有用的并发控制工具类。CountDownLatch\CyclicBarrier 和Semaphore 提供了一种并发流程控制的手段,Exchanger 工具类提供了线程间交换数据的一种手段。
1.CountDownLatch:CountDownLatch 允许一个或多个线程等待其他线程完成操作。
CountDownLatch 是通过“共享锁” 实现的。 在创建 CountDownLatch 时,会传递一个 int 类型参数, 该参数是“锁计数器” 的初始状态, 表示该“共享锁”最 多 能 被 count 个 线 程 同 时 获 取 , 这 个 值 只 能 被 设 置 一 次 , 而 且CountDownLatch 没有提供任何机制去重新设置这个计数值。 主线程必须在启动其他线程后立即调用 await()方法。 这样主线程的操作就会在这个方法上阻塞, 直到其他线程完成各自的任务。 当某线程调用该 CountDownLatch 对象的await()方法时, 该线程会等待“共享锁” 可用时, 才能获取“共享锁” 进而继续运行。 而“共享锁” 可用的条件, 就是“锁计数器” 的值为 0! 而“锁计数器”的初始值为 count, 每当一个线程调用该 CountDownLatch 对象的 countDown()方法时, 才将“锁计数器” -1; 通过这种方式, 必须有 count 个线程调用countDown()之后, “锁计数器” 才为 0, 而前面提到的等待线程才能继续运行!
场景:解析一个Excel里的多个sheet数据,使用多个线程,每个线程解析一个sheet,等到所有线程解析完,主线程完成解析
解决方案一:
在主线程中调用启动每一个线程,然后调用个线程的.join()方法。
解析:join()用于让当前线程等待join线程执行结束,就是不停检查join线程是否存活,如果存活则让当前线程永远等待。直到join线程执行结束后 this.notifyAll().
public class Test {
public static void main(String[] args) {
final CountDownLatch latch = new CountDownLatch(2);
new Thread(){
public void run() {
try {
System.out.println("子线程"+Thread.currentThread().getName()+"正在执行");
Thread.sleep(3000);
System.out.println("子线程"+Thread.currentThread().getName()+"执行完毕");
latch.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
};
}.start();
new Thread(){
public void run() {
try {
System.out.println("子线程"+Thread.currentThread().getName()+"正在执行");
Thread.sleep(3000);
System.out.println("子线程"+Thread.currentThread().getName()+"执行完毕");
latch.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
};
}.start();
try {
System.out.println("等待2个子线程执行完毕...");
latch.await();
System.out.println("2个子线程已经执行完毕");
System.out.println("继续执行主线程");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
CountDownLatch 的构造函数接受一个int类型的参数作为计数器,如果想等待N个线程完成,这里传入N。
public void countDown() { }; //将count值减1
public void await() throws InterruptedException { }; //调用await()方法的线程会被挂起,它会等待直到count值为0才继续执行
同步屏障 CyclicBarrier
让一组线程达到一个同步点时被阻塞,知道最后一个线程达到同步点时候,屏障才会开们,所有被拦截的线程才会继续执行。await()函数每被调用一次,计数便会减少 1(CyclicBarrier 设置了初始值),并阻塞住当前线程。 当计数减至 0 时, 阻塞解除, 所有在此 CyclicBarrier 上面阻塞的线程开始运行。
场景:假若有若干个线程都要进行写数据操作,并且只有所有线程都完成写数据操作之后,这些线程才能继续做后面的事情。
public class Test {
public static void main(String[] args) {
int N = 4;
CyclicBarrier barrier = new CyclicBarrier(N);
for(int i=0;i
解析:当调用await()方法之后,线程就处于barrier了,知道所有线程达到同步点以后可以继续处理别的事情。
3.CountDownLatch 和 CyclicBarrier 的区别
(1) CountDownLatch 的作用是允许 1 个线程等待其他线程执行完成之后,它才执行; 而 CyclicBarrier 则是允许 N 个线程相互等待到某个公共屏障点, 然后这一组线程再同时执行。
(2) CountDownLatch 的计数器的值无法被重置, 这个初始值只能被设置一次, 是不能够重用的; CyclicBarrier 是可以重用的。
Semaphore
可以控制某个资源可被同时访问的个数, 通过构造函数设定一定数量的许可, 通过 acquire() 获取一个许可, 如果没有就等待, 而 release() 释放一个许可。
场景:要读取几万个文件的数据,可以启动几十个线程并发读取,同时需要连接数据库完成存储,而数据库连接数只有是个,这时候我们只有控制十个线程获取数据库的链接保存数据,否则报错无法获取链接。
public class SemaphoreTest{
private static final int THREAD_COUNT = 30;
private static ExecutorServicethreadPool = Executors.new FixedThreadPool(THREAD_COUNT);
private static Semaphore s =new Semaphore(10);
public static void main(String[] args){
for(int i=0;i
虽然有三十个线程在执行,但是只允许10个并发执行。acquire()获取一个许可证,release()方法归还一个许可证。
10 利用java来实现的阻塞队列的代码
public class MyBlockQueue {
//push锁
private final static Object pushLock = new Object();
//pop锁
private final static Object popLock = new Object();
//数据存储
private Stack stack;
//队列最大长度
private int maxSize = 0;
//队列最小长度
private int minSize = 0;
public MyBlockQueue(int size) {
this.maxSize = size;
stack = new Stack();
}
public synchronized void push(T t) {
if(stack.size() >= maxSize) {
pushLock();
}
stack.push(t);
popUnLock();
}
public synchronized T pop() {
if(stack.size() == minSize) {
popLock();
}
T t = stack.pop();
pushUnLock();
return t;
}
private void pushLock() {
synchronized (pushLock) {
try {
pushLock.wait();
} catch (Exception e) {
e.printStackTrace();
}
}
}
private void pushUnLock() {
synchronized (pushLock) {
pushLock.notify();
}
}
private void popLock() {
synchronized (popLock) {
try {
popLock.wait();
} catch (Exception e) {
e.printStackTrace();
}
}
}
private void popUnLock() {
synchronized (popLock) {
popLock.notify();
}
}
}
11实现二叉树的翻转的实现
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public TreeNode invertTree(TreeNode root) {
//递归终止的条件
if(root==null){
return null;
}
//递归的过程是
invertTree(root.left);
invertTree(root.right);
//翻转实现
TreeNode temp=root.right;
root.right=root.left;
root.left=temp;
return root;
}
}
12 并发的相关的问题的原理?
……
13 java 中的IO 和NIO 和AIO的原理和区别?
简答
详细回答
14 拦截器 过滤器的原理 有什么区别?怎么配置?
过滤器是基于函数的回调的实现的可以所有的请求进行拦截,过滤器的实例化是能在容器初始化的时候执行 通常用于是的修改字符编码的,过滤请求中的敏感字符。在web.xml文件中配置
拦截器是基于的web框架的 原理是基于的java的反射的原理,是在一个方法的调用前后执行另外的一个方法。拦截器只能对controller请求进行拦截 jsp是不拦截的 在springmvc的配置文件中
监听器 实现了javax.servlet.ServletContextListener 接口的服务器端程序,它也是随web应用的启动而启动,只初始化一次,随web应用的停止而销毁。主要作用是:感知到包括request(请求域),session(会话域)和applicaiton(应用程序)的初始化和属性的变化;
15 反问环节:
我问他对我的面试评价,他是叫我猜。然后笑笑说,这个东西我不做评价了。后面的结果会通知到你的。那个时候就知道你的评价了。
面试总结:
1java的基础中的那几个关键字和一些词语的区别和理解
类 多态 抽象类 接口 并发问题的关键字的理解和原理…………
2并发编程的中的原理和简单实现
3 手写代码一般都是leetcode的简单的一定要手写一次成功。不能在IDEA中的写,难度是简单的就行。