- 作者题解链接 题解链接
原文链接 开发者社区> 面试一点通> 正文
1.基于BIO实现的Server端,当建立了100个连接时,会有多少个线程?如果基于NIO,又会是多少个线程? 为什么?
-
BIO:默认,同步阻塞IO流, 每个获取的连接都需要创建一个新的处理线程,故需要
100
个处理线程,服务端还需要一个1个Accept线程来接受连接请求;所以当连接建立后,将这个连接的IO读写放到一个专门的处理线程,所以当建立100个连接时,通常会产生1个Accept线程 + 100个处理线程
。 -
NIO: 同步非阻塞IO流, NIO通过事件来触发。
a.NIO有Selector,通过while循环检查或系统调用通知,检查多个channel的状态是否可读写,所以可以用1个线程
管理多个channel。NIO在处理IO的读写时,当从网卡缓冲区读或写入缓冲区,这个过程是串行的,所以用太多线程处理IO事件其实也没什么意义,连接事件由于通常处理比较快,用1个线程去处理就可以。
b.IO事件呢,通常会采用cpu core数+1或cpu core数 * 2
,这个的原因是IO线程通常除了从缓冲区读写外,还会做些比较轻量的例如解析协议头
等,这些是可以并发的,为什么不只用1个线程处理,是因为当并发的IO事件非常多时,1个线程的效率不足以发挥出多core的CPU的能力,从而导致这个地方成为瓶颈,这种在分布式cache类型的场景里会比较明显,按照这个,也就更容易理解为什么在基于Netty等写程序时,不要在IO线程里直接做过多动作,而应该把这些动作转移到另外的线程池里去处理,就是为了能保持好IO事件能被高效处理。 从上面可以看出,对于大多数需要建立大量连接,但并发读写并不会同时的场景而言,NIO的优势是非常明显的。
2.通常来说基于NIO实现的Server端,会用多少个线程去处理IO事件,为什么?
- 问的是Server端会用多少个线程去处理IO事件
- 2*cpu核数 或 cpu核心数+1 左右 该答案参考自:http://www.sohu.com/a/298857998_494946
3. 一个典型的客户端集群->LB->服务端集群这样的结构中,如客户端采用连接池,长连接的方式,这种设计你觉得可能会出现什么问题?如果客户端采用的是单个长连接的方式呢?如果有问题,你觉得应该怎么解决?
LB 即LoadBlance(负载均衡,如nginx)
a. 如客户端采用连接池,长连接的方式,长连接建立后一般不会断开,也就是某个client会固定请求到某台server,随着扩容缩容、服务器上下线,会负载不均衡。
b. 解决方案:比较根本的解决方法是在这样的场景里把中间的LB去掉,换成类似通过服务注册/发现的机制来解决。重启负载高的机器.不用LB.
4.cglib和Java的动态代理相比,具体有什么不同?
- 说白了就是SpringAop的两个实现模式,扔个连接(AOP-snailclimb)[https://snailclimb.gitee.io/javaguide/#/docs/system-design/framework/spring/Spring?id=aop]; 在Java中一般采用JDK动态代理模式,Spring AOP 同时支持 CGLIB、ASPECTJ、JDK动态代理
a.cglib 通过字节码操作生成代理, 能够对类做代理
b.JDK通过反射接口生成代理,所以被代理类必须有实现接口。
(不是很懂,先扔着) 5. 在基于Netty实现FrameDecoder时,下面两种代码的表现会有什么不同?
第一种的处理方式可以有效减少IO线程池和业务处理线程池的上下文切换,从而提高IO线程的处理效率。
6. 用Executors.newCachedThreadPool创建的线程池,在运行的过程中有可能产生的风险是?
阿里规范不建议这么做, Executors.newCachedThreadPool()会一直创建大量线程直到OOM.
7. new ThreadPoolExecutor(10,100,10,TimeUnit.MILLISECONDS,new LinkedBlockingQueue(10));一个这样创建的线程池,当已经有10个任务在运行时,第11个任务提交到此线程池执行的时候会发生什么,为什么?
此题考查ThreadPoolExecutor的workQueue [工作、阻塞队列]的简单用法, 所以应该第11个任务会加进队列中,而非开启第11个线程来处理。
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}
workQueue如下:
1) 同步阻塞队列:core-》max-》超出max后直接抛异常 ,
2) 链表阻塞队列:先core-》队列-》max-》再抛异常,速度快点;
3)数组,有界;
4)延迟队列:用于定时任务
5)优先级..
8. 实现一个自定义的ThreadFactory的作用通常是?
- 通常的作用是给线程取名字,便于以后查问题,查日志。
- 用法
public class ThreadFactoryMain implements ThreadFactory{
private final String groupName;
private AtomicInteger nextId = new AtomicInteger(1);
public ThreadFactoryMain(String groupName) {
this.groupName = "ThreadFactoryMain -" + groupName + "-worker-";
}
@Override
public Thread newThread(@NotNull Runnable r) {
String threadName = groupName + nextId.incrementAndGet(); // 名称中添加一个自增的id
Thread thread = new Thread(null,r,threadName,0);
return thread;
}
}
———————————————
原文链接:https://blog.csdn.net/z69183787/article/details/91126481
9. 除了用Object.wait和Object.notifyAll来实现线程间的交互外,你还会常用哪些来实现?
考查JUC包, 也就是Java并发控制的常见机制
java的JUC包里的不管是BlockingQueue的实现,还是各种类似CountDownLatch、CyclicBarrier,都可以用来实现线程的交互。
CountDownLatch: 倒计数门闩,https://www.cnblogs.com/zhazhaacmer/p/11365805.html
CyclicBarrier: 循环栅栏,维持最低的线程并发量
BlockingQueue: 阻塞队列,常见三类使用方式,阻塞式、超时式、查询完直接返回式对资源取拿
参考:https://blog.csdn.net/zhou920786312/article/details/100175698
10. 为什么ConcurrentHashMap可以在高并发的情况下比HashMap更为高效?
分段式锁,以及巧妙的使用final、volatile,
参考:https://snailclimb.gitee.io/javaguide/#/docs/java/Multithread/并发容器总结?id=二-concurrenthashmap
11. AtomicInteger、AtomicBoolean这些类之所以在高并发时高效,共同的原因是?
CAS+volatile机制,例如AtomicInteger 类主要利用 CAS (compare and swap) + volatile 和 native 方法来保证原子操作,从而避免 synchronized 的高开销,执行效率大为提升。
参考:https://snailclimb.gitee.io/javaguide/#/docs/java/Multithread/Atomic?id=1-atomic-原子类介绍
12. 请合理的使用Queue来实现一个高并发的生产/消费的场景,给些核心的代码片段。
例如通常可能会借助LinkedBlockingQueue来实现简单的生产/消费, 或者使用BlockingQueue阻塞队列来对ftp线程池的线程进行管理,频繁的存取和释放.
13. 请实现让10个任务同时并发启动,给些代码片段。
定时任务,QuartZ
或者使用JUC的CyclicBarrier: 循环栅栏,维持最低的线程并发量
14. 在Java程序运行阶段,可以用什么命令行工具来查看当前Java程序的一些启动参数值,例如Heap Size等。
ps -ef | grep java
jinfo -flags
15. 用什么命令行工具可以查看运行的Java程序的GC状况,请具体写出命令行格式。
jstat -gc pid 5000
jstat -gcutil [pid] [频率,例如多少毫秒一次] [多少次]
- 如果已经打开了gc log,可以直接查看gc日志。
- gc log通常怎么打开,具体的命令行参数,一段gc log的解读