多线程相关
死锁
死锁四个条件:
-
互斥条件
- 临界资源只能被一个线程拥有
-
占有且等待
- 线程/进程拥有补发临界资源,但同时请求另外一些临界资源
-
占有不释放
- 在请求到其它临界资源前,已拥有的临界资源不会被释放
-
循环链
- 多个线程/进程形成循环请求链
饥饿
线程一直不能获得所需要的资源,如:低优先级线程请求资源一直被高优先级线程持有
多线程操作特性
-
原子性
- 操作不可中断
-
有序性
-
多线程操作是有序的,但可能出现cpu指令重排:
- cpu采用流水线指令模式,可能出现后面指令提前到前面执行
-
-
可见性
-
线程对临界资源的操作,其他线程能看到最新的临界资源
-
violate
-
保证有序性和可见性
-
临界资源发生变化时,强迫写到共享内存
-
-
线程状态
-
新建
- new
-
就绪
-
start:等待系统调度运行
-
yield:从运行切换到就绪,重新参与资源竞争
-
-
运行
- run
-
阻塞
-
join
-
sleep
-
suspend
-
-
结束
-
正常运行结束
-
stop: 不建议使用
-
-
中断
-
并不会中断线程,只是设置中断标识位
-
通过中断,使线程跳出阻塞状态(sleep等)
-
线程并发包:java.util.concurrent
-
synchronized
-
重入锁
- 线程可重复访问已获得的临界资源,无需释放和再申请锁
-
配合object.wait,object.notify实现多线程通信
-
使用前需获得锁
-
wait执行完后自动释放锁
-
notify/notifyall不会释放锁,只是发送一个通知,当同步块执行完后才会释放锁
-
-
-
重入锁:reentrantlock
-
重入锁
-
可设置优先响应中断,获得锁的过程中,可优先响应中断,避免死锁
-
可设置超时时长:获取的过程中,可设置等待时长
-
可设置是否为公平锁
-
公平锁:按申请的先后顺序获得锁
-
不公平锁:随机分配
-
-
可与condition(notify/signal)配合使用,实现多线程通信,类似synchronized+object.wait+object.notify
-
-
信号量:semaphone
- 实现多个线程同时访问临界资源
-
读写锁:writereadlock
-
读不阻塞
-
写阻塞
-
-
计时器:countdownlatch
- 计数为0时,线程访问临界资源,跳出阻塞
-
循环栅栏:cyclebarrier
- 类似countdownlatch,但可重复计数
-
locksupport
-
可实现线程的暂停和回复:park、unpark
-
即使先unpark在park也无问题,不像suppend和resume,resume发生在suppend前出问题
-
线程并发集合
-
concurrentmap
-
collections集合方法
-
copyandwritelist
-
blockingqueue
线程池
创建线程池的几个参数:
-
corepoolsize:核心线程数
-
maxnumpoolsize:最大线程数
-
keepalive:闲置线程(非核心线程)存活时间
-
unit:存活时间单位
-
workqueue:当无空闲线程处理任务时,任务放到该工作队列等待调度
- BlockingQueue实例,不同实例对应了不同调度策略和拒绝策略
-
threadfactory:线程创建工厂
-
handler:任务拒绝执行策略
CAS
-
比较并交换/无锁/乐观锁
-
a-b-a问题
-
线程x读取遍历z的值为a,线程y读取到z的值也为a,但此时z的值可能已经经过多次变化
-
可通过版本号优化
-
-
AutoInteger等
- 内部采用死循环获取临界资源方式,效率低
锁优化
-
锁持有时间
-
加锁粒度:细化、粗化
-
锁分离
JVM
参考:https://juejin.im/post/5b85ea54e51d4538dd08f601
java内存划分
-
堆
- 线程共享
-
方法区
- 线程共享
-
native栈
-
java栈
-
pc
java堆划分
-
新生代minor
-
eden区
-
对象一般分配在新生代的eden区,大对象和长期存活对象分配在老年代
-
eden区对象经过一次gc后,将移动到surrivor区,surrivor区经过n次(一般为15次)gc后,将移动到老年代
-
-
surrivor区
-
from区
-
to区
-
-
-
老年代major
-
永久代/元空间
java引用
-
强引用
-
软引用
-
弱引用
-
虚引用
java如何标识对象是否存活?
-
引用计数:循环计数问题
-
可达性分析:GCRoot
-
string对象存活:字符串无string对象引用
-
class存活:实例都释放,且加载它的classloader被释放
GC算法
-
标记清除
-
标记内存回收对象,再回收
-
效率高,但存在内存碎片问题
-
-
复制
- 将内存划分为两块,在其中一款分配对象,gc后,存活的对象移动到另外一块
-
标记整理
- 类似复制,但没有将内存划分为两块,只是在内存的一端分配对象,存活的对象移动到另外一端
-
分代回收
-
新生代:复制算法
- 频繁、快、高效
-
老年代:标记清除、标记整理
- 慢,低效,时间间隔久
-
-
常用gc处理器
-
串行
-
并发、并行:gc线程和用户线程
-
设计模式
六大原则
-
单一原则
- 类、接口、方法功能单一
-
里氏代换原则
- 子类应扩展父类抽象方法,但不应该扩展父类非抽象方法
-
依赖倒置原则
- 抽象不依赖细节,细节应该依赖抽象
-
接口隔离原则
- 接口方法尽量少,功能划分为多个接口
-
迪米特拉原则
- 类对依赖的类了解尽可能少,减少代码耦合
-
开放封闭原则
- 扩展开放,修改封闭
集合/数据结构
Collections
-
set
-
元素唯一
-
treeset
- 红黑树结构
-
hashset
- hash算法计算元素存放地址
-
-
list
-
arraylist
- 线性存储
-
vector
- 线程安全
-
linkedlist
-
可实现fifo、stack
-
同时实现了list和queue
-
-
-
queue
-
priorityqueue
- 优先队列
-
map
-
hashmap
-
数组+链表实现
-
多个数据的hash值相同时,通过链表连接
-
-
hashtable
- 线程安全
-
treemap
- 红黑树
-
linkedhashmap
-
基于双向链表实现的hashmap
-
支持插入排序和访问排序
- 访问排序:每次访问完后的元素放在链表头,lru算法
-
其他
-
hash指元素使用hash算法计算存储地址
-
link/tree,指元素是链表或者树的结构
IO
-
字节流
-
字符流
-
randomaccessfile
-
NIO
-
非阻塞、内存映射方式,面向块
-
channel
-
buffer
- 外部数据读写 与buffer交互
-
selector
- 异步IO
-
序列化
-
原理
-
java为序列化对象采用序列号机制,当序列化一个对象时,先检查该对象是否已经序列化
-
未序列化,采用流中数据构建,并为该对象关联一个序列号
-
已序列化,直接根据关联的序列号,获得该对象引用
-
-
-
版本号
-
根据类的超类、接口和域等属性计算得到,当上述信息发生变化时,版本号会发生变化
-
一般将版本号静态写死,防止序列化时版本号不一致发生异常
-
-
static、transient域和方法,不能被序列化
-
序列化产生新的对象(不调用构造函数),单例模式失效
创建对象的几种方式
-
调用构造函数
-
new
-
反射
-
序列化
- 不调用构造函数,通过二进制流构造
-
clone
- 不调用构造函数
其他
-
classloader
-
双亲委派模型
-
引导classloader
- 最顶层的加载类,主要加载核心类库,%JRE_HOME%\lib下的rt.jar、resources.jar、charsets.jar和class等
-
扩展classloader
- 加载目录%JRE_HOME%\lib\ext目录下的jar包和class文件
-
系统(应用)classloader
- 加载当前应用classpath所有类
-
常用算法
- 深搜,DFS
Node* DFS(Node* root,int data)
{
if(root.key == data)
return root;
Node*[] chids = data->childs();
for(Node* child : childs)
{
if(child.key == data)
return child;
DFS(child,data);
}
}
- 广搜
Node* BFS(Node* root,int data)
{
if(root.key == data)
return root;
FIFO<Node*> fifo = new FIFO<Node*>();
fifo.queue(root);
return BFS_Visit(fifo,data);
}
Node* BFS_Visit(FIFO<Node*> fifo,int data)
{
while(!fifo.isEmpty())
{
Node* item = fifo.dequeue();
if(item.key == data)
return item;
for(Node* child : item.childs())
fifo.queue(child);
}
}
-
排序
int quick_sort_part(int data[], int start, int end)
{
int i = start;
int j = start;
int key = end;
while (i <= end)
{
if (data[i] < data[key])
{
exchange(data[i], data[j]);
j++;
}
i++;
}
if (j != key)
{
exchange(data[j], data[key]);
}
return j;
}
//快速排序
void quick_sort(int data[], int start, int end)
{
if (start < end)
{
int k = quick_sort_part(data, start, end);
quick_sort(data, start, k - 1);
quick_sort(data, k + 1, end);
}
}
-
合并排序
-
堆排序
-
最大堆
-
最小堆
-
-
树
-
二叉树
-
二叉搜索树
-
b树
-
红黑树
-
网友评论