核心问题

分工

  1. JUC中的ExecutorFork/JoinFuture本质上都是一种分工方法
  2. 并发编程领域还总结了一些设计模式,基本上都是和分工方法相关
    • 生产者-消费者
    • Thread-Per-Message
    • Worker Thread

同步

  1. 在并发编程领域里的同步,主要指的就是_线程间的协作_
    • 一个线程执行完了一个任务,如何通知执行后续任务的线程开始工作
  2. 协作一般是与分工相关的
    • JUC中的ExecutorFork/JoinFuture本质上都是一种分工方法
    • 但同时也能解决线程协作的问题
  3. 例如,用Future可以发起一个异步调用
    • 当主线程调用get()方法取结果时,主线程会等待
    • 当异步执行的结果返回时,get()方法就自动返回了
    • Future工具类已经帮我们解决了_主线程和异步线程之间的协作_
  4. JUC中的CountDownLatchCyclicBarrierPhaserExchanger都是用来解决线程协作问题的
  5. 但很多场景还是需要自己处理线程之间的协作,问题基本可以描述为
    • 当某个条件不满足时,线程需要等待,当某个条件满足时,线程需要被唤醒执行
  6. 在Java并发编程领域,解决协作问题的核心技术管程(Monitor)
    • 上面提到的所有线程协作技术底层都是利用管程来解决的
    • 管程是一种解决并发问题的通用模型,除了能解决线程协作问题,还能解决互斥问题
    • 管程是解决并发问题的万能钥匙

互斥

  1. 分工和同步主要强调的是性能,线程安全关注的是_并发程序的正确性_
  2. 在并发程序里,当多个线程同时访问同一个共享变量时,结果是不确定
    • 导致不确定的主要源头可见性问题,有序性问题和原子性问题,为了解决这三个问题,Java引进来_Java内存模型_
    • Java内存模型提供了一系列规则,可以避免可见性问题,有序性问题和原子性问题,但_不能完全解决线程安全的问题_
  3. 解决线程安全问题的核心方案还是互斥,互斥的定义:_在同一时刻,只允许一个线程访问共享变量_
  4. 实现互斥的核心技术synchronized、JUC中的各种Lock都能解决互斥问题
  5. 锁解决了线程安全的问题,但同时也带来了性能问题,可以针对场景进行优化
    • JUC中的ReadWriteLockStampedLock可以优化在读多写少的场景下锁的性能
    • 无锁的数据结构,例如JUC中的原子类都是基于无锁技术实现的
    • 使用Copy-On-Write模式
    • 不共享变量(ThreadLocal)或者变量只允许读(final)
  6. 使用锁除了要注意性能之外,还需要注意死锁问题

小结

参考资料

Java并发编程实战