ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

快递100一面(Java)

2022-02-09 22:31:52  阅读:161  来源: 互联网

标签:Java Executors 队列 阻塞 链表 快递 线程 hash 100


面试邀请来得有突然,记录一下有些问题以及答案。

ArrayList 是线程安全的吗,怎样保证他线程安全。

原因:
其实大部分集合类都不是线程安全的,其关键的原因在于添加元素的底层实现,因为在arrayList的add()中:

elementData[size++] = e;

这一步包括了自增和赋值,因为当线程A执行了赋值以后,暂停转而运行其他的线程,但是还没扩容,就会导致,B线程的值直接覆盖A的值,

解决:
调用Collections.synchronizedList方法 ,其原理也就是将ArrayList里的方法添加synchronized关键字,也就是加锁,也就是经典的装饰器模式

HashMap会出现什么问题,如何解决?

首先HashMap是一个高效的数据结构,可以在O(1)时间复杂度查询数据,原理大致为:将Key通过Hash算法得到一个地址值,再获取内存中想要的数据,但是Hash算法存在缺陷,就是不同的Key值通过计算得到的地址值又很小的几率相同,这就是Hash冲突。
解决方法:

  1. 开放寻址法:
    它的核心思想就是重新探测新的位置来解决冲突,如何寻找新的地址:
    1.线性探测法:
    当向Hash表中插入数据时,发现该地址已经有数据了,那就从这个位置开始在数组中往后查找,直到找到空闲位置为止;缺点是随着不断填充,空闲的位置变少,探测的时间就会增加,
    2.二次探测法:
    探测的下标为hash(key)+0² 、 hash(key)+1² …
    3.双重哈希法:
    使用多个hash函数计算key ,如果第一个hash函数计算出来的地址被占用了,就调用第二个函数 ,直到找到空闲位置为止;

  2. 链表法:
    该方法更常用,原理为:在hash表中每一个桶或者槽(slot) 都会对应一个链表,将hash值相同的元素放到相同槽位的对应链表中,插入数据的时候,只需要通过hash函数计算出对应的hash值,然后添加到链表之后。链表法性能取决于hash函数的性能,尽量保证链表长度足够小。

如何创建一个线程池,其中的参数如何设置?

  1. 通过Executors类提供的静态方法Executors.newCachedThreadPool()
    创建一个可缓存的线程池,若线程数超过所需,缓存一段时间后会回收,若线程数不够,则新建线程,初始状态下线程池没有线程,而线程不足会自动创建线程。
  2. 通过Executors类提供的静态方法Executors.newFixedThreadPool(3);
    创建一个固定大小的线程池
  3. 通过Executors类提供的静态方法Executors.newScheduledThreadPool(3);
    创建一个周期性的线程池,支持定时及周期性执行任务。
private static void createScheduledThreadPool() {
        ScheduledExecutorService executorService = Executors.newScheduledThreadPool(3);
        System.out.println(DateUtil.now() + " 提交任务");
        for (int i = 0; i < 10; i++) {
            final int index = i;
            executorService.schedule(() -> {
                // 获取线程名称,默认格式:pool-1-thread-1
                System.out.println(DateUtil.now() + " " + Thread.currentThread().getName() + " " + index);
                // 等待2秒
                sleep(2000);
            }, 3, TimeUnit.SECONDS);
        }
    }

创建大小为3的线程池,设置定时时间为3秒

  1. 通过Executors类提供的静态方法Executors.newSingleThreadExecutor();
    创建只有一个线程的线程池
  2. 通过自定义ThreadPoolExecutor构造器(重要)
    ThreadPoolExecutor类提供了4种构造方法,可根据需要来自定义一个线程池。
    共有7个相关参数
    1. corePoolSize 核心线程数,线程池始终存活线程的数量
    2. maximumPoolSize 最大线程数,线程池中允许的最大线程数。keepAliveTime
    3. keepAliveTime 线程没有任务执行时最多保持多久时间会终止
    4. unit 时间单位
    5. workQueue 堵塞队列 有7中选择
    - ArrayBlockingQueue 一个由数组结构组成的有界阻塞队列。
    - LinkedBlockingQueue 一个由链表结构组成的有界阻塞队列
    - SynchronousQueue 一个不存储元素的阻塞队列,即直接提交给线程不保持它们。
    - PriorityBlockingQueue 一个支持优先级排序的无界阻塞队列。
    - DelayQueue 一个使用优先级队列实现的无界阻塞队列,只有在延迟期满时才能从中提取元素。
    - LinkedTransferQueue 一个由链表结构组成的无界阻塞队列。与SynchronousQueue类似,还含有非阻塞方法。
    - LinkedBlockingDeque 一个由链表结构组成的双向阻塞队列
    6. threadFactory 线程工厂 主要用来创建线程
    7. handler 拒绝策略 拒绝处理任务时的策略 4种
    - AbortPolicy 直接拒绝 抛出异常
    - CallerRunsPolicy 重试 再次调用运行该任务的execute()
    - DiscardOldestPolicy 抛弃头部(最旧) 的任务,并执行当前任务
    - DiscardPolicy 抛弃当前任务

JVM虚拟就内存结构:
我把它分为两类:线程公有 线程私有
java堆和方法区是线程共有的
java栈、本地方法栈、PC寄存器是每个线程独有一份

  1. 方法区主要是保存类的信息以及各种静态变量和常量;
  2. java堆主要保存实例对象
  3. java栈是程序方法运行的结构,每个方法都单独存入栈中,各自存有局部变量表操作数栈、以及动态链接和方法出入口
  4. 本地方法栈是为以native关键字修饰的方法服务
  5. PC寄存器是记录下一条需要执行的字节码指令

待续

标签:Java,Executors,队列,阻塞,链表,快递,线程,hash,100
来源: https://blog.csdn.net/coding_deliver/article/details/122849509

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有