HashMap的源码分析
HashMap基于散列表,散列表中每一个Node节点(桶)是链表,当两个条目(entry)的key的hash值对桶数(capacity)取模的值相等时,这两个entry会存储在同一个链表中。但当链表中元素达到一定数目时,链表结构会转变为树结构。
本文从初始化,扩容,插入,获取,删除这几个方面深入讨论了HashMap的实现细节。
...此文中没有讨论
HashMap中涉及到树结构的源码。
HashMap基于散列表,散列表中每一个Node节点(桶)是链表,当两个条目(entry)的key的hash值对桶数(capacity)取模的值相等时,这两个entry会存储在同一个链表中。但当链表中元素达到一定数目时,链表结构会转变为树结构。
本文从初始化,扩容,插入,获取,删除这几个方面深入讨论了HashMap的实现细节。
...此文中没有讨论
HashMap中涉及到树结构的源码。
使用synchronized关键字对整个方法加锁(防止其他线程访问整个方法)往往会带来更大的性能开销,如果你只想保护某些代码块,可以使用同步代码块,这一段被锁保护的代码块就称为临界区( critical section ),前面的显式锁所保护的区域以及使用synchronized保护的代码块都是临界区。
Java 函数式接口和Lambda表达式是 Java 8 中引入的一个重要概念,它允许你将行为作为参数传递给方法,从而实现更简洁、更灵活的代码。
Lambda表达式是一个可传递的代码块,可以在以后执行一次或多次。
...要创建一个任务,通常实现Runnable接口。不幸的是,Runnable接口的run()方法返回void,因此,其并不适合处理计算任务。
考虑一个经典的问题:用多线程分段计算0-100的加和,我们需要把每个线程计算的值汇总,然后再求和,那么应该怎样获取每个任务返回值呢?
Java提供了Callable和Future接口,使任务有提供返回值的能力。
集合框架中一个重要的类,其实是Collection接口的伴随类,其中定义了许多实用方法,用来获取集合视图,或提供一些方便的操作集合元素的算法。
由于视图是直接封装的Collection接口,因此其方法有些局限,并且由于特殊的设计,部分操作是不允许的(会抛出 UnsupportedOperationExceptin )。
...将一个类定义在另一个类的内部,这就是内部类。
...定义言简意赅 ,内涵丰富多彩。
Java有能力使任务为等待某些条件成立而进入阻塞状态,所以就有可能出现这样一种情况:某个任务在等待另一个任务,而后者又在等待其他的任务,这样一直等待下去,直到等待链上的最后一个任务又在等待第一个任务释放锁,这样就出现了任务之间相互等待的连续循环现象,这种情况出现之后,没有哪个任务能够执行,于是 死锁 出现。
死锁之所以难以规避,其重要的原因就在于其不确定性,可能程序运行良好,但是有潜在的死锁风险,这个风险在某些域的初始条件变化时,变得特别大,导致程序很快死锁。同时,死锁难以复现,当程序出现死锁时,往往只能通过jvm的堆栈日志来探究原因。
...一般地,如果程序运行良好,任务执行完所需操作后自然结束,任务终结。
如果任务执行时出现异常,任务也会终结。
在设计多个线程协同工作的任务时,需要判断任务终结的条件,以便合适地终结任务,这点尤为重要。
在本节中主要讨论在多线程协同工作的情况下,如何合适的终结任务。
...在讨论线程协作的时候,已经讨论了生产者与消费者雏形,比如录音是生产者,而播放则是消费者;同样的,在汽车打蜡的模型中,打蜡可看作生产者,抛光可看作消费者;只是它们的关系是简单的生产-消费关系。
除了简单的线程协同之外,Java提供了同步队列来解决线程的协同问题,本节重点讨论这部分的内容。
...上一篇文章介绍了juc的几种主要阻塞队列。
本文使用2个例子,演示了阻塞队列在Java中的应用。
...