• 【刷面试题】阿里毕玄:来测试下你的Java编程能力


    原文链接 开发者社区> 面试一点通> 正文

    阿里毕玄:来测试下你的Java编程能力

    1.基于BIO实现的Server端,当建立了100个连接时,会有多少个线程?如果基于NIO,又会是多少个线程? 为什么?

    1. BIO:默认,同步阻塞IO流, 每个获取的连接都需要创建一个新的处理线程,故需要100个处理线程,服务端还需要一个1个Accept线程来接受连接请求;所以当连接建立后,将这个连接的IO读写放到一个专门的处理线程,所以当建立100个连接时,通常会产生1个Accept线程 + 100个处理线程

    2. 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事件,为什么?

    1. 问的是Server端会用多少个线程去处理IO事件
    2. 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的动态代理相比,具体有什么不同?

    1. 说白了就是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的作用通常是?

    1. 通常的作用是给线程取名字,便于以后查问题,查日志。
    2. 用法
    
    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的解读
  • 相关阅读:
    css概述五
    css概述四
    css概述三
    css概述二
    css概述
    Python的第三方web开发框架Django
    Python中的模块和包
    SQL语句优化
    数据库向Excel写入数据
    动态拼接sql语句
  • 原文地址:https://www.cnblogs.com/zhazhaacmer/p/12249964.html
Copyright © 2020-2023  润新知