本文主要对Java并发编程里面常用的线程池、线程状态、线程协同、锁进行了总结,这些几乎是Java面试里面必问的内容,特别是线程池的参数,不仅要能讲出具体的参数有哪些和参数的意义,也要对一个新线程submit到线程池后,线程池是如何进行处理的流程了然于胸。

Java并发编程

  1. 线程池
    1. 线程
  • 创建线程的方法
    实现Runnable或Callable接口
    继承Thread类

1.2. 线程池类型

  • NewFixedThreadPool
    固定线程大小,无边界队列

  • NewWorkStealingPool
    实际的线程数不固定,也不保证线程的执行顺序

  • NewSingleThreadPool
    单线程,无边界队列

  • NewCachedThreadPool
    适合执行时间较短的任务,只要线程不够则新建

  • NewScheduledThreadPool
    定时执行线程

1.3. ThradPoolExecutor线程池参数

  • corePoolSize
    核心线程数
  • maximumPoolSize
    最大线程数
  • keepAliveTime
    超过核心线程数的线程,最大的存活时间
  • unit
    存活时间单位
  • workQueue
    任务队列
  • handler
    如果已经超过最大线程数,继续有新的线程处理类
    AbortPolicy
    直接抛出RejectExecutionException异常
    CallerRunsPolicy
    重试添加当前的任务
    DiscardOldestPolicy
    抛弃最老的任务
    DiscardPolicy
    抛弃当前的任务

1.4. BlockingQueue
1.4.1. 实现类
ArrayBlockingQueue
数组实现队列
LinkedBlockingQueue
链表实现队列
PriorityBlockingQueue
优先级队列
可自定义Comparator
DelayQueue
延时获取元素队列,队列的元素需要实现Delayed接口
SynchronousQueue
不存储元素的阻塞队列,只有在消费者试图获取元素的时候生产者才能插入元素
LinkedTransferQueue
transfer(E e)
若存在消费者线程,即立刻移交; 否则插入元素到队尾
tryTransfer(E e)
若存在消费者线程,即立刻移交; 否则返回fasle
tryTransfer(E e, long timeout, TimeUnit unit)
若存在消费者线程,即立刻移交; 否则插入元素到队尾,如果指定时间内没有被消费,则返回false并将元素移除
LinkedBlockingDeque
双向阻塞队列
1.4.2. 常用方法
add(E)
超过容量抛出异常
offer(E)
超过容量返回false
put(E)
超过容量阻塞
offer(E,long,TimeUnit)
超过容量并插入超时返回false
take()
为空则阻塞
poll(long,TimeUnit)
为空并获取超时则返回null
remove(Object)
删除特定元素

2. 线程状态

2.1. 新建
2.2. 就绪
2.3. 阻塞
2.4. 运行
2.5. 死亡

3. 线程协同

3.1. CountDownLatch
用于某个线程等待其他线程执行完成之后它才执行,不可重用

3.2. CyclicBarrier
用于一组线程池互相等待至某个状态,然后这组线程再同时执行,可重用

3.3. Semaphore
资源使用控制

3.4. Exchanger
两个线程同时交换数据

3.5. Thread.join()
等待子线程执行完成,执行完成之后可以执行主线程

4. 锁

4.1. synchronized
4.1.1. 三个阶段
偏向锁
在对象头上的Mark Word部分设置线程ID
轻量级锁
轻量级锁依赖CAS操作Mark Word来试图获取锁
重量级锁
monitorenter和monitorexit
4.1.2. 不可重入锁

4.2. ReentrantLock
4.2.1. 可重入锁
基于AQS来实现,首先尝试用CAS(LOCK_IF_MP)来获取锁,如果没有获取到,就加入到FIFO的链表里面,然后锁如果被释放了,通知链表里面的第一个节点获取锁
4.2.2. 提供了Condition用于线程间通信
4.2.3. 提供了tryAcquire方法,用于超时没有获取到锁的处理

4.3. ReentrantReadWriteLock
写线程访问时,所有的读和其他写线程都阻塞

5. 容器类

5.1. ConcurrentHashMap
5.2. CopyOnWriteArrayList
5.3. ConcurrentLinkedQueue
5.3.1. 和LinkedQueue相比没有poll操作
5.4. LinkedHashMap
5.4.1. 和HashMap相比,遍历Map的时候会根据插入顺序来遍历
5.5. HashMap
5.5.1. 如何扩容?
节点数大于阈值的时候触发扩容
直接扩大两倍,然后需要将老桶的数据迁移到新桶,所以并发的时候会有问题

6. happen before

线程的启动与停止
加锁与解锁
volatile变量的读和写
读的时候确认方法区的共享变量有没有更新
程序顺序原则
传递性原则

7. 常见问题

7.1. 如何解决Atomic类CAS操作时产生的ABA问题?
使用AtomicStampedReference给对象加上版本号

Contents
  1. 1. 2. 线程状态
  2. 2. 3. 线程协同
  3. 3. 4. 锁
  4. 4. 5. 容器类
  5. 5. 6. happen before
  6. 6. 7. 常见问题