1 CAS--Compare And Swap

最原初的锁,比较然后交换。Cpu硬件保证的原子性。抢不到就一直抢=自旋=while(if)

java.util.concurrent.atomic包下用的就是CAS。

这种不将资源锁起来就操作的锁叫做乐观锁。八股文喜欢说CAS有什么问题,进而引出ABA问题,但我觉得这样引出容易误导,ABA问题本就不是CAS考虑范围内的,而不是一开始有什么设计缺陷。

AtomicStampedReference

当要求改的是1时刻的A变量,但实际上2时刻的A被另一线程改成B,最后又改为A(ABA问题)。CAS不知道,只看变量对上了就去执行,就出错了。就引入了一个版本号机制,多判断一个版本号(也可以用时间戳)。Java有AtomicStampedReference实现了版本号控制的CAS。

2 AQS--AbstractQueuedSynchronizer

被称为悲观锁,就是默认难抢到,也就意味着要维护一个表示着资源数量的state(上锁),一个放在待处理的线程的队列FIFO。还有一个待实现的各具特色的处理释放资源的方法。

状态state
state是volatile修饰的,并被并发修改,所以修改state的方法都需要保证线程安全。

FIFO队列

  1. AQS会维护一个等待的线程队列,把线程都放到这个队列里,这个队列是双向链表形式。
  2. AQS就是”排队管理器”,当多个线程争用同一把锁时,必须有排队机制将那些没能拿到锁的线程串在一起。当锁释放时,锁管理器就会挑选一个合适的线程来占有这个刚刚释放的锁。

实现获取/释放等方法
这里的获取和释放方法,是利用AQS的协作工具类里最重要的方法,是由协作类自己去实现的,并且含义各不相同;需要每个实现类重写tryAcquire和tryRelease等方法。

Semaphore

CountDownLatch

用于让线程等待其他线程先完成操作在执行。一般用于线程要依赖其他线程完成后才能动的情况。

ReentrantLock

用于独占加锁、解锁,支持同一线程反复加锁(可重入)

CyclicBarrier

CyclicBarrier 允许一组线程互相等待,直到到达一个公共的屏障点。
当所有线程都到达这个屏障点后,它们可以继续执行后续操作,并且这个屏障可以被重置循环使用。

3 Java 关键字

Synchronized

java提供优化过的锁。自适应改变加锁机制,底层是用C++写的

  1. 无锁:还未有线程来过。
  2. 偏向锁:也就是默认只有一个线程会来抢,所以只记线程ID(第一次也还是CAS去抢ID),之后对上ID就用
  3. 轻量锁:其实就是少量线程开始并发了,CAS去抢锁。
  4. 重量锁:CAS自旋抢不到浪费CPU资源,就会进入阻塞休眠
_owner // 当前持有锁的线程 
_recursions // 重入次数计数器!!! 
_EntryList // 抢不到锁,阻塞排队的线程(入口队列) 
_WaitSet // 调用wait(),休眠等待的线程(等待队列) 
_cxq // 竞争自旋队列

volatile

volatile关键字可以保证可见性,但不能保证原子性,因此不能完全保证线程安全。volatile关键字用于修饰变量,当一个线程修改了volatile修饰的变量的值,其他线程能够立即看到最新的值,从而避免了线程之间的数据不一致。

实现线程启动

线程方法

ThreadLocal

每个线程有一个私有空间,为ThreadLocalMap。以ThreadLocal为key,值为value存数据。

4 Executors

先创建核心线程池,然后队列,队列也满了创建非核心线程,全满了就拒绝。非核心线程空闲后会被回收。

线程池的创建

//获取CPU核心数 用于合理设置线程数
int corePoolSize = Runtime.getRuntime().availableProcessors() * 2;

//手动配置线程池
ThreadPoolExecutor threadPool = new ThreadPoolExecutor(
    corePoolsize,// 核心线程数 线程池长期维持的最小线程数
    corePoo1Size*2,//最大线程数线程池能容纳的最多线程数
    60L,//非核心线程存活时间,多久后销毁
    TimeUnit.SECONDS,//存活时间单位
    new ArrayBlockingQueue<>(100),//任务阻塞队列 核心线程忙时 新任务存这里
    Executors.defaultThreadFactory(),//线程创建工厂 用于设置线程名 优先级等
    new ThreadPoolExecutor.AbortPolicy()
);// 拒绝策略 队列满且线程数达最大时 如何处理新任务

拒绝策略

线程池种类