知识点总结

2 篇文章 0 订阅
2 篇文章 0 订阅

1.  关于java中常用的容器,集合,比如HashMap, ConcurrentHashMap。容器的初始容量,扩容机制,线程安全,JDK8做了哪些优化以及为什么要做这个优化。

        HashMap主要涉及的问题:

  1. 底层数据结构
  2. 初始化核心参数
  3. hash算法
  4. 寻址算法
  5. hash冲突,解决hash冲突的方法是什么,这里可以说一下ThreadLocal中解决hash冲突的方法,以及为什么这里用链地址法,ThreadLocal中用线性探测法。
  6. 扩容机制
  7. put方法,get方法和remove方法执行流程
  8. hashMap为什么线程不安全

        ConcurrentHashMap主要涉及的问题:

  1. 底层数据结构
  2. hash算法
  3. put方法流程,get方法,remove方法,size方法
  4. jdk1.7和1.8底层实现的区别,包括1.7如何去锁segment

     参考文章:

      HashMap是头插法还是尾插法  这篇文章讲了为什么要把JDK7的头插法改成尾插法

      从存储结构、常用方法分析、扩容以及安全性等方面深入讲解HashMap的工作原理

      彻头彻尾理解 ConcurrentHashMap

       hashmap扩容时死循环问题


2.  线程池相关的问题, 最好把线程池的源码看一遍。

     线程池中的worker继承AQS,实现了不可重入锁,主要是为了通过有锁,无锁标识worker处于   忙碌状态还是空闲状态,从而可以判断是否对woker进行销毁。参考文章: ThreadPoolExecutor关闭线程池原理


3. AQS的源码过一遍,里面有很多知识点可以总结出来:

     参考我的博客: AQS源码总结。 

     说一下平时常用的,什么地方用到了AQS,比如ConcurrentHashMap中用到了分段锁,对segment进行加锁,Segment 类继承于 ReentrantLock 类,从而使得 Segment 对象能充当锁的角色。

    /**
     * Segments are specialized versions of hash tables.  This
     * subclasses from ReentrantLock opportunistically, just to
     * simplify some locking and avoid separate construction.
     */
    static final class Segment<K,V> extends ReentrantLock implements Serializable {

        /**
         * The number of elements in this segment's region.
         */
        transient volatile int count;    // Segment中元素的数量,可见的

        /**
         * Number of updates that alter the size of the table. This is
         * used during bulk-read methods to make sure they see a
         * consistent snapshot: If modCounts change during a traversal
         * of segments computing size or checking containsValue, then
         * we might have an inconsistent view of state so (usually)
         * must retry.
         */
        transient int modCount;  //对count的大小造成影响的操作的次数(比如put或者remove操作)

        /**
         * The table is rehashed when its size exceeds this threshold.
         * (The value of this field is always <tt>(int)(capacity *
         * loadFactor)</tt>.)
         */
        transient int threshold;      // 阈值,段中元素的数量超过这个值就会对Segment进行扩容

        /**
         * The per-segment table.
         */
        transient volatile HashEntry<K,V>[] table;  // 链表数组

        /**
         * The load factor for the hash table.  Even though this value
         * is same for all segments, it is replicated to avoid needing
         * links to outer object.
         * @serial
         */
        final float loadFactor;  // 段的负载因子,其值等同于ConcurrentHashMap的负载因子

        ...
    }

        线程池中的内部类Worker,继承了AQS,实现了不可重入锁。

        

private final class Worker
        extends AbstractQueuedSynchronizer
        implements Runnable
    {
        /**
         * This class will never be serialized, but we provide a
         * serialVersionUID to suppress a javac warning.
         */
        private static final long serialVersionUID = 6138294804551838833L;

        /** Thread this worker is running in.  Null if factory fails. */
        final Thread thread;
        /** Initial task to run.  Possibly null. */
        Runnable firstTask;
        /** Per-thread task counter */
        volatile long completedTasks;

        /**
         * Creates with given first task and thread from ThreadFactory.
         * @param firstTask the first task (null if none)
         */
        Worker(Runnable firstTask) {
            setState(-1); // inhibit interrupts until runWorker
            this.firstTask = firstTask;
            this.thread = getThreadFactory().newThread(this);
        }

4.   并发安全集合和线程池知识点, 并发安全集合要了解常用的几种,以及知道在什么场景用。CopyOnWriteArrayList用的是写时复制的思想,多用于读多写少的场景,在Redis的持久化机制中,Fork出的子进程跟父进程是共享代码空间,数据空间不共享。用的也是写时复制的思想。

     参考博客:  并发安全集合和线程池


5.    volatile, cas和synchronized原理

        synchronized原理

        重点说一下思路:

  1.  为了解决处理器和主存之间的速度鸿沟,引入高速缓存,却又导致了缓存一致性问题
  2.  为了解决缓存一致性问题,引入了如MESI等技术,又导致了处理器等待问题
  3.  为了解决处理器等待问题,引入了写缓冲区和无效队列,又导致了重排序和可见性问题
  4.  为了解决重排序和可见性问题,引入了内存屏障
  5.  每个技术点都可以举例工作中的场景或者源码中的场景,知道它的原理和用法。比如volatile(AQS中state concurrentHashMap中的Node节点),线程池的ctl(atomic 高三位:线程池状态 低位:线程池worker线程数量), concurrentHashMap(cas+synchronized),工作中优化停机,心跳时间等。

     技巧: 参考文章,jstack分析线程等待、死锁问题关于synchronized原理,可以结合jstack线程追踪命令讲解下。我们在用jstack进行线程追踪的时候会看到线程的状态信息,比如:

NEW,未启动的。不会出现在Dump中。

RUNNABLE,在虚拟机内执行的。运行中状态,可能里面还能看到locked字样,表明它获得了某把锁。

BLOCKED,受阻塞并等待监视器锁。被某个锁(synchronizers)給block住了。

WATING,无限期等待另一个线程执行特定操作。等待某个condition或monitor发生,一般停留在park(), wait(), sleep(),join() 等语句里。

TIMED_WATING,有时限的等待另一个线程的特定操作。和WAITING的区别是wait() 等语句加上了时间限制 wait(timeout)。

TERMINATED,已退出的。

         还可以看到线程状态产生的原因,这块就可以结合上面那篇文章讲一下synchronized的原理

runnable:状态一般为RUNNABLE。

in Object.wait():等待区等待,状态为WAITING或TIMED_WAITING。

waiting for monitor entry:进入区等待,状态为BLOCKED。

waiting on condition:等待区等待、被park。

sleeping:休眠的线程,调用了Thread.sleep()。

6.   ThreadLocal相关的知识点

        说ThreadLocal的时候,可以讲一下里面的几个关键点:

        1.包括弱引用,空间整理,解决哈希冲突的方法等;

        2. 说一下ThreadLocal的缺陷,没法解决父子线程间值传递;

        3. 说一下InheritableThreadLocal,讲一下InheritableThreadLocal怎么解决这个问题的,以及它又会存在如果线程复用的话,无法传递值的问题;

        4. 为了解决这个问题,阿里开源了TransmittableThreadLocal,用于解决“在使用线程池等会缓存线程的组件情况下传递ThreadLocal”问题的InheritableThreadLocal扩展。如果要用Ttl在线程池与主线程间传递,需要配合TtlRunnable和TtlCallable使用。

        5. 最后,看一下这篇文章,ThreadLocal空间整理,可以知道threadlocal虽然解决了线程之间的变量隔离,但是存在一些缺陷,为了解决这个问题,FastThreadLocal用空间换时间,可以对ThreadLocal的操作时间进行优化。参考文章:Netty源码分析——FastThreadLocal框架设计

        6. 看下这篇文章,专属成自己的语言,可以说成是你自己项目中遇到并且解决的。细数ThreadLocal三大坑,内存泄漏仅是小儿科


7.  JVM相关知识点——内存区域

        参考文章: 聊聊JVM的垃圾收集

        主要介绍分为那几块模型以及1.7和1.8方法区的位置,从放堆中移到了本地内存,这块区域不受JVM控制。


8. JVM相关知识点——如何判断对象是否可以被回收

        参考文章: 聊聊JVM的垃圾收集

        介绍一下两种方法,引用计数法和可达性分析法。说一下这两种方法的区别。

        关于可达性分析法,需要从GC Root往下搜索,需要知道哪些对象可以作为GC Root。


9. JVM相关知识点——常见的垃圾收集算法

        参考文章:聊聊JVM的垃圾收集

        

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值