- 浏览: 77608 次
最新评论
-
kevinflynn:
...
ThreadLocal 源码分析 -
kevinflynn:
[url=aaaa][/url]
ThreadLocal 源码分析 -
kevinflynn:
学习到了 感谢楼主。
ThreadLocal 源码分析
文章列表
http请求报文格式:
请求方法 空格 URL 协议版本 回车 换行
头部字段名称:值 回车 换行
头部字段名称:值 回车 换行
空行
请求体
http响应报文格式:
协议版本 空格 状态码 空格 状态码描述 回车 换行
头部字段名称:值 回车 换行
头部字段名称:值 回车 换行
空行
响应体
java 守护线程:
只要 JVM 中尚存一个非守护线程(用户线程),守护线程就工作,例如(GC).当所有的非守护线程退出的时候,守护线程随同 JVM 一起停止工作.
守护进程:
脱离控制台在后台运行的进程.
孤儿进程:
没有父进程的子进程,子进程又 init 接管回收
僵尸进程:
当父进程开启了一个子进程的时候,子进程先于父进程结束,此时,父进程由于忙而没有调用 wait 方法,此时可以用 ps 查看到子进程显示 Z(僵尸进程).
二叉查找树(又:二叉排序树)
一颗m阶二叉查找树应具备如下特征:
1.若左子树不为空,那么左子树的关键字应比根节点小
2.若右子树不为空,那么右子树的关键字应比根节点大
3.左子树和右子树都为二叉查找树
平衡二叉树(又:AVL 树)
1.左子树和右子树的深度查的绝对值 <= 1
B-树
B-树的关键是:指针+关键字+地址
一颗 m 阶的 B- 树具备如下特征:
1.所有节点最多 m 颗子树
2.若根节点不为空,则至少2颗子树
3.除根节点之外的所有非终端节点最少 (m/2)向上取整颗子树.
B+树
一颗 m 阶 B+ 树和一颗 m 阶 B- 树的差异:
...
String 类在 Java 开发中是用到的最常见的类之一,今天说一说 String 类的 lastIndexOf 方法.
这个方法给我很奇怪的是 fromIndex 的取值.
用过 String 类 indexOf 方法的都知道,fromIndex 是从 0 开始的,比如说:
有一个字符串:
String str = "helloworld";
str.indexOf("ow", 1) 是可以在 str 中匹配到的.
但是
str.lastIndexOf("ow", 1) 能匹配到吗?
给我们的感觉是不是能匹配到,从 1 ...
堆排序思路:建立大根堆或小根堆,然后堆顶就是有序的,将堆顶和数组的最后一个元素对调位置,那么最后一个元素就是最大的元素,然后调整堆,将堆顶元素和数组倒数第二个元素对调位置,以此类推,重复,就能得到排序序列了.
实现:
/**
* 堆排序.
* 思路:第一步建立大根堆.
*/
@Test
public void testHeapSort(){
int[] arr = {4,2,5,1,2,9,8,3,5,6,2,8};
// 从最后一个非叶子节点开始进行调整.
for(int i=arr.length ...
外部排序:需要对超出内存容量的待排序列进行排序. 怎么做了?采用局部有序,最后合并,序列化到磁盘上.
比如说:待排序列有 10M 大小,而内存只有 1M.
现在怎么做了?
1.将 10M 大的待排序列分成10块,每块1M,先对每个 1M的数据进行排序.
2.将排序后的两个1M数据读一个就比较一个,写到缓冲区去,当缓冲容量到 1M时序列化到磁盘上,然后继续比较,以此类推,最终就可以将待排序列排序好.
希尔排序思路概括来说是:分组 + 插入排序.
/**
* 希尔排序
* 思路:希尔排序,是缩小增量排序, 需要分组. 对每个分组实行直接插入排序.
* 最好的情况:O(nlog2n)
* 最坏的情况:O(n ^ 2)
* 不稳定
* 使用情况:中等大小规模
*/
@Test
public void testShellSort(){
int[] arr = {4,2,5,1,2,9,8,3,5,6,2,8};
// 分组 + 直接插入排序.
for(int i= ...
插入排序分两种:
1.直接插入排序
直接插入排序默认一个已经有序的集合,然后把待排节点插入到这个有序集合中去.
/**
* 直接插入算法:
* 思路:将一个元素插入到一个已经有序的集合中去.
* 最好的情况是:O(n).
* 最坏的情况是:O(n ^ 2).
* 稳定算法.
* 使用:当 n 很小的时候,适用,当 n 很大的时候,则不宜采用该算法.
*/
@Test
public void testDirectInsertSort(){
int[] arr = {4,2,5,1,2,9,8 ...
1.MySQL 体系结构:
最上层的 JDBC 相当于一个抽象,针对不同的数据库,编写同样的数据库连接代码,可以连接不同的数据库,例如(MySQL/Oracle/Sybase等)
连接池
然后是在插件化的存储引擎之上的定义语言,解析器,优化器,缓存等.
插件化的存储引擎
文件系统 + 日志
2.存储引擎:
InnoDB: 支持事务,行锁设计、支持外键、默认读不会产生锁
MyISAM: 不支持事务,表锁设计,支持全文索引,MyISAM 的缓冲池只缓存索引文件
NDB: 数据全部放在内存中,用于集群
Memory: 将表中的数据放在内存中,如果重启或崩溃,数据丢失,默认使用哈希索引,只 ...
AtomicInteger 是如何实现原子操作的了?
答案是 CAS(compare and swap)
CAS是 Java Unsafe 类中实现的一些 native 方法,底层代码使用 c/c++ 编写,java 通过 jni 进行调用,在底层芯片级别保证原子操作的进行.
举个例子:假设有两个线程执行 i++ 语句,初始时 i = 0. 那么最终的输出结果可能不为 2. 因为 Java 内存模型的缘故,导致一个线程的修改还没有更新到主存中,另一个线程也进行了修改,最终的结果可能是 1.
简介:
就是一个 put 操作必须和 take 操作对应. 如果一下来了三个 put 操作,那么结果是这样的:
head->put1->put2->put3.
put1/put2/put3 都自旋一小会,如果还没有 take 来的话,就都调用 LockSupport.part 自我阻塞.
实现原理:
基于队列的实现原理:
还是上面的那个例子,假设一次性来了三个 put 操作,那么结果是这样的:
head->put1->put2->put3.
现在假设来了一个 take 操作,那么对首出队,唤醒第一个节点的线程. put1 这个操作就能够继续执行 ...
简介:
LinkedBlockingDeque 是一个双端队列,在队列的两头都能进行 put/offer 操作.我感觉这个类很鸡肋,效率不是很高,大而全.
实现原理:
LinkedBlockingDeque 底层使用一把锁(ReentrantLock)来控制入队出队操作.也就是说队列两头的操作来抢这一把锁. 所以这是我认为效率低下的原因.
使用场景:
LinkedBlockingDeque 使用在工作窃取模式下.
工作窃取模式:比如说有两个工人A和B,A和B关系很好,老板给A和B分配了任务. 由于A的任务复杂度较低,先做完了,B 还在做. 因为A和B是好哥们,A说,哥们,你从前面往 ...
简介:
写操作时上锁,然后拷贝一个新的数组,操作新数组,将当前数组的引用设置为 array,释放锁.
思想:
采用读写分离的思想。读是一个数组,写是一个新的数组。这样做的优点是对读操作就可以不用上锁访问了,缺点是不能保证数据实时一致性,只能保证数据最终一致。
其他方面的内容和 ArrayList 差不多,唯一的区别就在于 CopyOnWriteArrayList 在进行写操作的时候上锁了.
简介:
CyclicBarrier 实现这么一个功能,比如说吃饭,是不是要等所有人到齐了才能开始吃?CyclicBarrier 就实现了这么一个功能. 所有的线程都互相等待着,等所有的线程到达后,然后执行. CyclicBarrier 还可以实现这么一个功能,当所有人(线程)到齐后,可以先叫服务员上菜,然后所有人再开始吃.
实现原理:
使用 ReentrantLock.condition 实现的. 来一个线程,判断 count 自减后是否等于 0 ,不等于 0 ,则调用 wait 方法自我阻塞,等于 0 ,先执行传入的 runnable 线程,然后唤醒所有的线程.
CyclicBarrie ...
介绍:
Semaphore 用于对某一物理或逻辑资源被同一时间访问数量的限制.
实现:
Semaphore 是如何做到对某一物理或逻辑资源访问数量的限制了?
答案是 AQS.
比如我定义:Semaphore(10), 同一时刻只能有 10 个线程访问线程池,每来一个线程,state -1,当第11线程访问的结果是啥了?由于 state < 0 而被阻塞.
当一个线程访问完后,调用 release 方法,state + 1. 然后唤醒等待访问线程池的线程.
注意:
由于 release 方法中,没有对 state < 0 进行判断,每调用一次 release 方法 stat ...