一、线程基础
参考链接:Java多线程-合集
1.1 基本概念
??进程是操作系统进行资源分配的基本单位,而线程是操作系统进行调度的基本单位,即CPU分配时间的单位 。
- 原子性:和数据库事务中的原子性一样,满足原子性特性的操作是不可中断的,要么全部执行成功要么全部执行失败。
- 可见性:一个线程对变量的值进行了修改,其他线程能够立即得知这个修改。
- 有序性:程序执行的顺序按照代码的先后顺序执行。
1.2 AQS-抽象队列同步器
AbstractQueuedSynchronizer
https://www.jianshu.com/p/8eadabbcc5a9
1.3 线程池
线程池
1.4 同步/异步/阻塞/非阻塞
- 同步与异步描述的是进程/线程相互通信的方式,同步是由调用者主动等待调用的结果,异步是被调用者通过状态、通知等通知调用者, 或通过回调函数处理调用。
- 阻塞和非阻塞描述的是进程/线程在进行I/O操作时的状态,阻塞是指调用结果返回之前,当前线程会被挂起,非阻塞是指在不能立刻得到结果之前,该函数不会阻塞当前线程,而会立刻返回。
https://www.zhihu.com/question/19732473
https://blog.csdn.net/qq_39515350/article/details/120854214
二、JUC包
- volatile:单例模式-DCL(双端检测)机制。
instance = new Test();
//读取到的instance不为null,instance引用对象可能没有完成初始化
memory = allocate(); // 1 分配对象内存空间
instance(memory); // 2 初始化对象
instance = memory; // 3 设置instance指向分配的内存地址,此时!=null
步骤2和3不存在数据依赖关系,可能存在指令重排
- CAS:底层原理-自旋锁 & Unsafe类(底层汇编),时间戳原子引用解决ABA问题。
//AtomicInteger#getAndIncrement
public final int getAndIncrement() {
//this-当前对象 valueOffset-内存地址偏移量
return unsafe.getAndAddInt(this, valueOffset, 1);
}
//Unsafe类
public final int getAndAddInt(Object var1, long var2, int var4) {
int var5;
do {
//主内存真实的值 不断自旋-获取主内存的值
var5 = this.getIntVolatile(var1, var2);
//var5 + var4更新值返回 true -- 自旋 比较值
} while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));
return var5;
}
- List:CopyOnWriteArrayList
//写时复制思想,读写分离
public boolean add(E e) {
final ReentrantLock lock = this.lock;
lock.lock();
try {
Object[] elements = getArray();
int len = elements.length;
Object[] newElements = Arrays.copyOf(elements, len + 1);
newElements[len] = e;
setArray(newElements);
return true;
} finally {
lock.unlock();
}
}
- Set:CopyOnWriteArraySet
//底层也是CopyOnWriteArrayList
public CopyOnWriteArraySet() {
al = new CopyOnWriteArrayList<E>();
}
- Map:ConcurrentHashMap
- CountDownLatch:使一个线程等待其他线程各自执行完毕后再执行
- CyclicBarrier:让所有线程都等待完成后才会继续下一步行动
- Semaphore:1)用于多个共享资源的互斥使用 2)用于并发线程数的控制
CountDownLatch一般用于某个线程A等待若干个其他线程执行完任务之后,它才执行;而CyclicBarrier一般用于一组线程互相等待至某个状态,然后这一组线程再同时执行;另外,CountDownLatch是不能够重用的,而CyclicBarrier是可以重用的。Semaphore和锁类似,它一般用于控制对某组资源的访问权限。
- 死锁:两个或两个以上的线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力干涉它们都将无法推进下去。
jps -l
jstack -l pid > jstack.out
https://fastthread.io/
- ThreadPool:控制运行的线程数量,底层是阻塞队列。
CPU密集型:任务需要大量的计算,没有阻塞,CPU一致全速运行;公式:CPU核数+1个线程的线程池。
I/O密集型:公式:2*CPU核数;公式:CPU核数/(1-阻塞系数),阻塞系数在0.8~0.9之间。
//获取PCU核数
Runtime.getRuntime().availableProcessors()
ThreadLocal:把ThreadLocal看成一个全局Map<Thread, Object>,每个线程获取ThreadLocal变量时,总是使用Thread自身作为key。相当于给每个线程都开辟了一个独立的存储空间,各个线程的ThreadLocal关联的实例互不干扰。
锁:对象锁是用来控制实例方法之间的同步,而类锁是用来控制静态方法(或者静态变量互斥体)之间的同步的。
https://www.shangmayuan.com/a/5845a0a8e2dc4e86b7f3c143.html