前言


Mysql索引原理


索引目的

索引的目的在于提高查询效率,可以类比字典,如果要查“mysql”这个单词,我们肯定需要定位到m字母,然后从下往下找到y字母,再找到剩下的sql。如果没有索引,那么你可能需要把所有单词看一遍才能找到你想要的,如果我想找到m开头的单词呢?或者ze开头的单词呢?是不是觉得如果没有索引,这个事情根本无法完成?

阅读更多

HashMap和HashSet都是collection框架的一部分,它们让我们能够使用对象的集合。collection框架有自己的接口和实现,主要分为Set接口,List接口和Queue接口。它们有各自的特点,Set的集合里不允许对象有重复的值,List允许有重复,它对集合中的对象进行索引,Queue的工作原理是FCFS算法(First Come, First Serve)。

首先让我们来看看什么是HashMap和HashSet,然后再来比较它们之间的分别。

什么是HashSet


HashSet实现了Set接口,它不允许集合中有重复的值,当我们提到HashSet时,第一件事情就是在将对象存储在HashSet之前,要先确保对象重写equals()和hashCode()方法,这样才能比较对象的值是否相等,以确保set中没有储存相等的对象。如果我们没有重写这两个方法,将会使用这个方法的默认实现。

public boolean add(Object o)方法用来在Set中添加元素,当元素值重复时则会立即返回false,如果成功添加的话会返回true。

阅读更多

LRU缓存介绍


我们平时总会有一个电话本记录所有朋友的电话,但是,如果有朋友经常联系,那些朋友的电话号码不用翻电话本我们也能记住,但是,如果长时间没有联系了,要再次联系那位朋友的时候,我们又不得不求助电话本,但是,通过电话本查找还是很费时间的。但是,我们大脑能够记住的东西是一定的,我们只能记住自己最熟悉的,而长时间不熟悉的自然就忘记了。

其实,计算机也用到了同样的一个概念,我们用缓存来存放以前读取的数据,而不是直接丢掉,这样,再次读取的时候,可以直接在缓存里面取,而不用再重新查找一遍,这样系统的反应能力会有很大提高。但是,当我们读取的个数特别大的时候,我们不可能把所有已经读取的数据都放在缓存里,毕竟内存大小是一定的,我们一般把最近常读取的放在缓存里(相当于我们把最近联系的朋友的姓名和电话放在大脑里一样)。

阅读更多

概述


我们在之前的博文中了解到关于HashMap和Hashtable这两种集合。其中HashMap是非线程安全的,当我们只有一个线程在使用HashMap的时候,自然不会有问题,但如果涉及到多个线程,并且有读有写的过程中,HashMap就不能满足我们的需要了(fail-fast)。在不考虑性能问题的时候,我们的解决方案有Hashtable或者Collections.synchronizedMap(hashMap),这两种方式基本都是对整个hash表结构做锁定操作的,这样在锁表的期间,别的线程就需要等待了,无疑性能不高。

所以我们在本文中学习一个util.concurrent包的重要成员,ConcurrentHashMap。

ConcurrentHashMap的实现是依赖于Java内存模型,所以我们在了解ConcurrentHashMap的前提是必须了解Java内存模型。但Java内存模型并不是本文的重点,所以我假设读者已经对Java内存模型有所了解。

阅读更多

概述

LinkedList和ArrayList一样,都实现了List接口,但其内部的数据结构有本质的不同。LinkedList是基于链表实现的(通过名字也能区分开来),所以它的插入和删除操作比ArrayList更加高效。但也是由于其为基于链表的,所以随机访问的效率要比ArrayList差。
看一下LinkedList的类的定义:

1
2
3
4
public class LinkedList<E>
extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, java.io.Serializable
{}

LinkedList继承自AbstractSequenceList,实现了List、Deque、Cloneable、java.io.Serializable接口。AbstractSequenceList提供了List接口骨干性的实现以减少实现List接口的复杂度,Deque接口定义了双端队列的操作。

阅读更多

ArrayList概述


ArrayList可以理解为动态数组,用MSDN中的说法,就是Array的复杂版本。与Java中的数组相比,它的容量能动态增长。ArrayList是List接口的可变数组的实现。实现了所有可选列表操作,并允许包括 null 在内的所有元素。除了实现 List 接口外,此类还提供一些方法来操作内部用来存储列表的数组的大小。(此类大致上等同于 Vector 类,除了此类是不同步的。)

每个ArrayList实例都有一个容量,该容量是指用来存储列表元素的数组的大小。它总是至少等于列表的大小。随着向ArrayList中不断添加元素,其容量也自动增长。自动增长会带来数据向新数组的重新拷贝,因此,如果可预知数据量的多少,可在构造ArrayList时指定其容量。在添加大量元素前,应用程序也可以使用ensureCapacity操作来增加ArrayList实例的容量,这可以减少递增式再分配的数量。

注意,此实现不是同步的。如果多个线程同时访问一个ArrayList实例,而其中至少一个线程从结构上修改了列表,那么它必须保持外部同步。(结构上的修改是指任何添加或删除一个或多个元素的操作,或者显式调整底层数组的大小;仅仅设置元素的值不是结构上的修改。)

我们先学习了解其内部的实现原理,才能更好的理解其应用。

阅读更多

LinkedHashSet概述


思考了好久,到底要不要总结LinkedHashSet的内容= = 我在之前的博文中,分别写了HashMap和HashSet,然后我们可以看到HashSet的方法基本上都是基于HashMap来实现的,说白了,HashSet内部的数据结构就是一个HashMap,其方法的内部几乎就是在调用HashMap的方法。

LinkedHashSet首先我们需要知道的是它是一个Set的实现,所以它其中存的肯定不是键值对,而是值。此实现与HashSet的不同之处在于,LinkedHashSet维护着一个运行于所有条目的双重链接列表。此链接列表定义了迭代顺序,该迭代顺序可为插入顺序或是访问顺序。

看到上面的介绍,是不是感觉其与HashMap和LinkedHashMap的关系很像?

注意,此实现不是同步的。如果多个线程同时访问链接的哈希Set,而其中至少一个线程修改了该Set,则它必须保持外部同步。

阅读更多

LinkedHashMap概述


HashMap是无序的,HashMap在put的时候是根据key的hashcode进行hash然后放入对应的地方。所以在按照一定顺序put进HashMap中,然后遍历出HashMap的顺序跟put的顺序不同(除非在put的时候key已经按照hashcode排序号了,这种几率非常小)

JAVA在JDK1.4以后提供了LinkedHashMap来帮助我们实现了有序的HashMap!

LinkedHashMap是HashMap的一个子类,它保留插入的顺序, 如果需要输出的顺序和输入时的相同,那么就选用LinkedHashMap。

LinkedHashMap是Map接口的哈希表和链接列表实现,具有可预知的迭代顺序。此实现提供所有可选的映射操作,并允许使用null值和null键。此类不保证映射的顺序,特别是它不保证该顺序恒久不变。

阅读更多

概述


和HashMap一样,Hashtable也是一个散列表,它存储的内容是键值对。
Hashtable在Java中的定义为:

1
2
3
public class Hashtable<K,V>  
extends Dictionary<K,V>
implements Map<K,V>, Cloneable, java.io.Serializable{}

从源码中,我们可以看出,Hashtable继承于Dictionary类,实现了Map, Cloneable, java.io.Serializable接口。其中Dictionary类是任何可将键映射到相应值的类(如 Hashtable)的抽象父类,每个键和值都是对象(源码注释为:The Dictionary class is the abstract parent of any class, such as Hashtable, which maps keys to values. Every key and every value is an object.)。但在这一点我开始有点怀疑,因为我查看了HashMap以及TreeMap的源码,都没有继承于这个类。不过当我看到注释中的解释也就明白了,其Dictionary源码注释是这样的:NOTE: This class is obsolete. New implementations should implement the Map interface, rather than extending this class. 该话指出Dictionary这个类过时了,新的实现类应该实现Map接口。

阅读更多

HashSet概述


对于HashSet而言,它是基于HashMap实现的,底层采用HashMap来保存元素,所以如果对HashMap比较熟悉了,那么学习HashSet也是很轻松的。

我们先通过HashSet最简单的构造函数和几个成员变量来看一下,证明咱们上边说的,其底层是HashMap:

1
2
3
4
5
6
7
8
9
10
11
12
private transient HashMap<E,Object> map;

// Dummy value to associate with an Object in the backing Map
private static final Object PRESENT = new Object();

/**
* Constructs a new, empty set; the backing <tt>HashMap</tt> instance has
* default initial capacity (16) and load factor (0.75).
*/

public HashSet() {
map = new HashMap<>();
}

其实在英文注释中已经说的比较明确了。首先有一个HashMap的成员变量,我们在HashSet的构造函数中将其初始化,默认情况下采用的是initial capacity为16,load factor为0.75。

阅读更多