源码 十月 23, 2019

源码系列-HashMap源码

文章字数 10k 阅读约需 9 mins.

首先看一下Map家族四个常用的实现类,分别是HashMap、Hashtable、LinkedHashMap和TreeMap。

下面我们主要解读HashMap,结合源码,从存储结构、常用方法分析、扩容以及安全性等方面深入解读HashMap的工作原理。

从结构实现来讲,HashMap是数组+链表+红黑树(JDK1.8增加了红黑树部分)实现的,如下图所示:

引入了红黑树是因为它查找、插入、删除的平均时间复杂度为O(log(n))。这是因为当产生hash碰撞时,数据会挂载(尾插),形成链表。链表空间上不连续,逻辑上连续,增删元素快,只需处理节点间的引用,时间复杂度为O(1),查询慢,需要遍历所有节...

查看全文

源码 十月 23, 2019

源码系列-HashMap源码

文章字数 10k 阅读约需 9 mins.

首先看一下Map家族四个常用的实现类,分别是HashMap、Hashtable、LinkedHashMap和TreeMap。

下面我们主要解读HashMap,结合源码,从存储结构、常用方法分析、扩容以及安全性等方面深入解读HashMap的工作原理。

从结构实现来讲,HashMap是数组+链表+红黑树(JDK1.8增加了红黑树部分)实现的,如下图所示:

引入了红黑树是因为它查找、插入、删除的平均时间复杂度为O(log(n))。这是因为当产生hash碰撞时,数据会挂载(尾插),形成链表。链表空间...

查看全文

并发 九月 05, 2019

并发编程之LockSupport

文章字数 2.6k 阅读约需 2 mins.

LockSupport提供的park/unpark是以线程的角度来设计,真正解耦了线程之间的同步。

  • park()方法,对当前线程执行阻塞操作,直到获取到可用许可后才解除阻塞,也就相当于当前线程进入阻塞状态。

    park 方法还可以在其他任何时间“毫无理由”地返回,因此通常必须在重新检查返回条件的循环里调用此方法。park不会释放当前线程占有的锁资源。

  • parkNanos(long)方法,对当前线程执行阻塞操作,等待获取到可用许可后才解除阻塞,最大的等待时间由传入的参数来指定,一旦超过最大时...

查看全文

并发 九月 05, 2019

并发编程之AQS原理剖析

文章字数 4.4k 阅读约需 4 mins.

AQS全称是AbstractQueuedSynchronizer,即抽象同步队列。下面看一下AQS的类图结构:

在AQS中维持了一个volatile修饰的单一共享状态state,来实现同步器同步。其更新采用乐观锁思想的CAS算法。

CLH(Craig, Landin, and Hagersten locks) 同步队列 是一个FIFO双向队列,其内部通过节点head和tail记录队首和队尾元素,队列元素的类型为Node。AQS依赖它来完成同步状态state的管理,当前线程如果获取同步状态失败时...

查看全文

八月 23, 2019

并发编程之锁

文章字数 2.4k 阅读约需 2 mins.

乐观锁

乐观锁认为一个线程去拿数据的时候不会有其他线程对数据进行更改,所以不会上锁。

实现方式:CAS机制、版本号机制

悲观锁

悲观锁认为一个线程去拿数据时一定会有其他线程对数据进行更改。所以一个线程在拿数据的时候都会顺便加锁,这样别的线程此时想拿这个数据就会阻塞。比如Java里面的synchronized关键字的实现就是悲观锁。

实现方式:就是加锁。

排他锁

该锁一次只能被一个线程所持有。比如synchronized、ReentrantLock

共享锁

该锁可以被多个线程所持有,比如ReentrantReadWrit...

查看全文

八月 07, 2019

并发编程之死锁、活锁、饥饿

文章字数 2.6k 阅读约需 2 mins.

死锁是指两个或两个以上的进程(线程)在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程(线程)称为死锁进程(线程)。

死锁产生的四个必要条件

  • 互斥条件:线程(进程)对于所分配到的资源具有排它性,即一个资源只能被一个线程(进程)占用,直到被该线程(进程)释放
  • 请求与保持条件:一个线程(进程)因请求被占用资源而发生阻塞时,对已获得的资源保持不放。
  • 不剥夺条件:线程(进程)已获得的资源在...
查看全文

并发 七月 15, 2019

并发编程之上下文切换

文章字数 1.3k 阅读约需 1 mins.

CPU通过时间片分配算法来循环执行任务,当前任务执行一个时间片后会切换到下一个任务。但是,在切换前会保存上一个任务的状态,以便下次切换回这个任务时,可以再加载这个任务的状态。所以任务从保存到再加载的过程就是一次上下文切换。

上下文切换过高,会导致CPU像个搬运工,频繁在寄存器和运行队列直接奔波 ,更多的时间花在了线程切换,而不是真正工作的线程上。直接的消耗包括CPU寄存器需要保存和加载,系统调度器的代码需要执行。间接消耗在于多核 cache之间的共享数据。

  • 使用Lmbench可以测量上下文切...
查看全文

JAVA基础 七月 05, 2019

java基础之HashMap与ConcurrentHashMap重点解读

文章字数 3.4k 阅读约需 3 mins.

HashMap 说明
底层结构 1. JDK1.8之前:数组+链表
2. JDK1.8:数组+链表/红黑树
链表与红黑树之间的转换:
链表->红黑树:链表长度大于等于8且数组长度(hash桶)大于等于64的时候
红黑树->链表:红黑树的节点数量小于等于6的时候退化为链表
元素特性 key、value可以为null,只能有一个key为null的键值对,允许有多个value为null的键值对
hash桶的数量 默认16,加载因子默认0.75(HashMap也许是按照lazy-...
查看全文

JAVA基础 六月 28, 2019

Java基础之intern方法

文章字数 2.3k 阅读约需 2 mins.

String.intern() 方法可以使得所有含相同内容的字符串都共享同一个内存对象。

JVM 中,存在一个字符串常量池,字符串的值都存放在这个池中。当调用 intern 方法时,如果字符串常量池中已经存在该字符串,那么返回池中的字符串;否则将此字符串添加到字符串常量池中,并返回字符串的引用。

JDK1.6 中,常量池在方法区。JDK1.7 中,常量池移到堆区了。

JDK1.6

  • 字符串常量池有该字符串,则返回字符串常量池中的引用。
  • 字符串常量池没有该字符串,会拷贝字符串至字符串常量池。

JDK1...

查看全文

REDIS 六月 05, 2019

redis专题-热点key解决方案

文章字数 2.5k 阅读约需 2 mins.

热key问题就是,突然有几十万的请求去访问redis上的某个特定key。那么,这样会造成流量过于集中,达到物理网卡上限,从而导致这台redis的服务器宕机。

  1. 凭借业务经验,进行预估哪些是热key
  2. 在客户端进行收集
    在操作redis之前,加入一行代码进行数据统计。
  3. 在Proxy层做收集
  4. 用redis自带命令
    • monitor命令,该命令可以实时抓取出redis服务器接收到的命令,然后写代码统计出热key是啥。但是该命令在高并发的条件下,有内存增暴增的隐患,还会降低redis的性能。
    • hotkeys...
查看全文

REDIS 五月 21, 2019

redis专题-必知必会的基础知识

文章字数 7.6k 阅读约需 7 mins.

优点

  • 读写性能优异, Redis能读的速度是110000次/s,写的速度是81000次/s。
  • 支持数据持久化,支持AOF和RDB两种持久化方式。
  • 支持事务,Redis的所有操作都是原子性的,同时Redis还支持对几个操作合并后的原子性执行。
  • 数据结构丰富,除了支持string类型的value外还支持hash、set、zset、list等数据结构。
  • 支持主从复制,主机会自动将数据同步到从机,可以进行读写分离。
    缺点
  • 数据库容量受到物理内存的限制,不能用作海量数据的高性能读写,因此Redis适合的场...
查看全文
加载更多
0%