1.hashmap
1.1 put方法过程
a.首先判断哈希桶是否为空 如果是添加第一个键值对 则要初始化一个数组
a.1 数组capacity的值为16,threhold的值为12
b.检查key是否为null 讨论不为null
b.1通过哈希算法计算key的hash值
b.2通过哈希值计算这个节点应该放在table数组的哪个位置上,table数组
每一个引用变量都是指向一个单向链表的
b.3遍历这个单向链表查找是否有这个key值 为了提高比较的速度
先比较hash值,hash值相等的话接下来再分两种情况
如果key没有重写equals方法的话直接用==比较
如果key重写了equals方法则用equals方法进行比较
如果key重复了的话就覆盖原先的value,并返回原先的值,方法结束
没有的话就开始真正添加新的节点
b.4将modcount这个属性值加一,这个modcount是用来记录map是否发生结构性变化的次数,
因为haspmap本身是非线程安全的,当通过迭代的方式遍历map中
的节点时,如果发生并发修改就会抛出concurrentmodificationexception
b.4.1 添加时要判断空间是否足够,不够时要进行扩容,扩容策略是将哈希桶的
size变为原来的两倍然后把原先的节点全部移植到新的table中,同时更新阈值threshold
b.4.2 空间足够的话直接将新节点插在对应单向链表的头部
b.5返回值为null
1.2 1.8和1.7的区别
a.1 jdk1.7中底层是由数组(也有叫做“位桶”的)+链表实现;jdk1.8中底层
是由数组+链表/红黑树实现
a.2 扩容后数据存储位置的计算方式也不一样
a.3 JDK1.7用的是头插法,而JDK1.8及之后使用的都是尾插法:因为JDK1.7是
用单链表进行的纵向延伸,当采用头插法就是能够提高插入的效率,但是也
会容易出现逆序且环形链表死循环问题。但是在JDK1.8之后是因为加入了红
黑树使用尾插法,能够避免出现逆序且链表死循环的问题。
1.3 维护
一个节点对象
包含的属性 K key、 V value、 int hash、 Entry<K,V> next
阈值threshold
加载因子 loadfactor
节点数目 size
指向结点的数组 table[]
2 LinkedList
内部类 Node
包含的属性 next Node prev Node E item
节点数 size
last Node first Node
3 多线程
3.1 多线程编程要保证满足三个特性
多线程编程要保证满足三个特性:原子性、可见性、有序性。
sleep yeild join
wait notify notifyall
run start
3.2 线程池
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {。。。}
3.2.1参数介绍
corePoolSize:线程池中核心线程数的最大值
maximumPoolSize:线程池中能拥有最多线程数
workQueue:用于缓存任务的阻塞队列,对于不同的应用场景我们可能会
采取不同的排队策略,这就需要不同类型的阻塞队列,在线程池中常用的阻塞
队列有以下2种:
SynchronousQueue<Runnable>:此队列中不缓存任何一个任务。向线程池提交任务时,如果没有空闲线程来运行任务,则入列操作会阻塞。当有线程来获取任务时,出列操作会唤醒执行入列操作的线程。从这个特性来看,SynchronousQueue是一个无界队列,因此当使用SynchronousQueue作为线程池的阻塞队列时,参数maximumPoolSizes没有任何作用。。
LinkedBlockingQueue<Runnable>:顾名思义是用链表实现的队列,可以
是有界的,也可以是无界的,但在Executors中默认使用无界的。
3.2.2以上三个参数之间的关系如下:
1) 如果没有空闲的线程执行该任务且当前运行的线程数少于corePoolSize,
则添加新的线程执行该任务。
2) 如果没有空闲的线程执行该任务且当前的线程数等于corePoolSize同时阻
塞队列未满,则将任务入队列,而不添加新的线程。
3) 如果没有空闲的线程执行该任务且阻塞队列已满同时池中的线程数小于ma
ximumPoolSize,则创建新的线程执行任务。
4) 如果没有空闲的线程执行该任务且阻塞队列已满同时池中的线程数等于ma
ximumPoolSize,则根据构造函数中的handler指定的策略来拒绝新的任务。
先corePoolSize 再queue 再maximumPoolSize 再 handler
3.2.3拒绝策略
ThreadPoolExecutor.AbortPolicy()
抛出RejectedExecutionException异常
ThreadPoolExecutor.CallerRunsPolicy()
由向线程池提交任务的线程来执行该任务
ThreadPoolExecutor.DiscardOldestPolicy()
抛弃最旧的任务(最先提交而没有得到执行的任务)
ThreadPoolExecutor.DiscardPolicy()
抛弃当前的任务
# 3.2.4常用线程池
newCachedThreadPool
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
newFixedThreadPool
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
newSingleThreadExecutor
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
newScheduleThreadPool
public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
new DelayedWorkQueue());
}
4 linux 常用命令
mkdir /data
mkdir -p /oldboy/test
ls -l /data
touch /data/oldboy.txt
使用vi/vim 编辑器
:q 退出
:wq 保存并退出
:q! 强制退出不保存
echo "I am studying linux" >oldboy.txt
cp /data/oldboy.txt /tmp/
mv /data/ /root/
cd /root/data
pwd
5 String
999.99%是使用StringBuilder
6 设计模式
模板方法 亨元模式 单例模式 动态代理模式 构建者模式 工厂模式
7.类加载过程
分配内存信息
给类变量赋默认值
从子到父
每个类除了保存类的类变量之外还保存着父类信息的引用
加载父类
查看父类是否已经加载 若没有加载则递归去加载父类
设置父子关系
执行类初始化代码
执行静态变量的赋值语句
从父到子:执行静态初始化代码父类开始再执行子类的
8.在类加载之后对象创建的过程
分配内存
分配的内存包括本类的实例变量和父类的实例变量
给实例变量赋初值
从子到父
每个对象除了保存类的实例变量之外还保存着实际类信息的引用
执行实例初始化代码
执行实例变量的赋值语句
从父到子:执行静态初始化代码父类开始再执行子类的