Java 并发
概念
thread
-
Runnable 无返回值
-
Callable -> Future
-
Executors
- 可以实现将 Runnable 对象转换成 Callable 对象
- Executors.callable(Runnable task)
-
ExecutorService 线程池的接口
- ThreadPoolExecutor
- 强制线程池不允许使用 Executors 去创建
- newCachedThreadPool
- 移除那些已有 60 秒钟未被使用的线程
- newFixedThreadPool
- 创建一个可重用固定线程数的线程池,以共享的无界队列方式来运行这些线程
- newScheduledThreadPool
- newSingleThreadExecutor
- 这个线程池只有一个线程
- 这个线程池可以在线程死后(或发生异常时)重新启动一个线程来替代原来的线程继续执行下去
- ThreadPoolExecutor
-
BLOCKED
- io.wait()
- lock
- sleep
- join
- 等待其他线程 die
- interrupt
- 调用 interrupt()方法并不会中断一个正在运行的线程
- 线程的 run 方法内部可以根据 thread.isInterrupted()的值来优雅的终止线程
- 给这个线程一个通知信号,会影响这个线程内部的一个中断标识位
- 这个线程本身并不会因此而改变状态(如阻塞,终止等)。
- 调用 interrupt()方法并不会中断一个正在运行的线程
lock
- 乐观锁
- java 中的乐观锁基本都是通过 CAS 操作实现的
- 在更新的时候会判断一下在此期间别人有没有去更新这个数据
- 采取在写时先读出当前版本号,然后加锁操作(比较跟上一次的版本号,如果一样则更新)
- 如果失败则要重复读-比较-写的操作
- CAS 是一种更新的原子操作(硬件来实现), 比较当前值跟传入值是否一样,一样则更新,否则失败
- 在使用 CAS 前要考虑清楚"ABA"问题是否会影响程序并发的正确性
- 如果需要解决 ABA 问题,改用传统的互斥同步可能会比原子类更高效
- 使用 AtomicStampedReference 是通过加版本号来解决 CAS 的 ABA 问题
- 只能保证一个共享变量的原子操作
- java 中的乐观锁基本都是通过 CAS 操作实现的
- 悲观锁
- synchronized
- 可重入锁
- 非公平锁
- 每个对象都有一个 monitor, 加锁就是在竞争 monitor
- 1.7/1.8 在对象头中有标记位, 不需要经过操作系统加锁
- 锁膨胀
- 偏向锁 -> 轻量级锁 -> 重量级锁
- AQS 框架下的锁先尝试 CAS 乐观锁去获取锁, 获取不到, 转换为悲观锁
- ReentrantLock
- 可中断, 公平锁, 多个锁
- conn.await / conn.signal
- wait / notify
- Semaphore 信号量
- acquire -> ReentrantLock.lockinterruptibly (可中断)
- AtomicReference
- AtomicInteger/ AtomicLong
- ReentrantReadWriteLock。
- ReentrantLock
- synchronized
- 自旋锁
- 让 CPU 空旋等待
- 适用于锁竞争不激烈的场景
- 1.6 引入适应性自旋锁
- 让 CPU 空旋等待
- 锁的状态总共有四种 (锁只能单向升级)
- 无锁状态
- 偏向锁
- 在只有一个线程执行同步块时进一步提高性能
- 轻量级锁
- 在线程交替执行同步块时提高性能
- 重量级锁
- 存在同一时间访问同一锁的情况,就会导致轻量级锁膨胀 为重量级锁
- 锁的优化
- 只有在有线程安全要求的程序上加锁
- 将大对象(这个对象可能会被更多线程访问), 拆成小对象
- 分段锁
- ConcurrentHashMap
- 分段锁
- 根据场景进行分离
- 读写锁
- 锁时间粗化
- 为了提高并发, 原则上应该让每个线程持有锁的时间尽量短
- 如果对同一个锁不停的进行请求、同步和释放,其本身也会消耗系统宝贵的资源,反而不利于性能的优化
- ReentrantLock 比 synchronized 的优势
- 等待可中断
- lock.lockInterruptibly
- 正在等待的线程可以选择放弃等待,改为处理其他事情
- 可实现公平锁
- 公平锁就是先等待的线程先获得锁
- ReentrantLock 默认情况是非公平的
- synchronized 只能是非公平锁
- 可实现选择性通知
- 线程对象可以注册在指定的 Condition 中,从而可以有选择性的进行线程通知,在调度线程上更加灵活
- 等待可中断
- valatile
- valatile 关键字线程同步的轻量级实现, 只能用于变量, 不能保证数据的原子性 (解决多线程之间的可见性)
- synchronized 关键字解决的是多个线程之间访问资源的同步性
并发的 3 个特性
- 原子性
- synchronized 保证代码片段的原子性
- 可见性
- volatile 解决共享变量在多个线程之间的可见性
- 有序性
- volatile 禁止指令进行重排序优化