1.并发编程的三个核心问题:
分工:
高效的拆解任务并分配给多个线程,例如Fork/Join框架就是一种分工模式
通俗来说,就是现实当中需要完成一个项目,项目经理需要将任务分配给不同的人员完成,Java SDK并发包中的Executor、Fork/Join、Future本质都是一种分工方法,再例如生产者-消费者模式,也是一直分工方法,映射到现实生活中就是餐厅的大厨和服务员,大厨负责炒菜并将菜放到窗口,服务员复制从窗口拿菜,如果不使用窗口,而采取大厨直接将菜递给服务员,那么大厨就需要等待服务员,从而效率降低,因此我们能够看出第一种分工模式明显好于第二种,由此我们也能明白分工的含义,就是高效的拆解任务并进行分配
同步:
指的是线程之间如何协作,CountDownLatch就是一种典型的同步方式
通俗来说,分工之后就是开工,执行过程中,任务之间肯定存在依赖,谁依赖再谁之后才能开工,而任务之间的沟通就需要依靠协作来完成,也就是说一个线程完成了任务,如果和通知后续的线程开展任务
协作一般都和分工相关,Java SDK中Executor、Fork/Join、Future本质都是分工方法,但是同时也能解决线程协作问题,
例如,用 Future 可以发起一个异步调用,当主线程通过 get() 方法取结果时,主线程就会等待,当异步执行的结果返回时,get() 方法就自动返回了。主线程和异步线程之间的协作,Future 工具类已经帮我们解决了
并发中的同步问题都可以描述为:当某个条件不满足时,线程需要等待,当某个条件满足时,线程需要被唤醒执行
Java并发编程领域,解决协作问题的核心技术是管程,管程是解决并发问题的通用模型,除了解决线程协作问题,还能解决互斥问题
互斥:
保证同一时刻只允许同一个线程访问共享资源,可重入锁就是一种典型的互斥手段
分工、同步如果强调的是性能,那么互斥就是为了解决程序的正确性,也就是线程安全性。而导致不确定性的源头就是可见性、原子性、有序性。为了解决这三个问题,Java引入了内存模型(JMM),JMM提供了一系列规则,利用这些规则我们可以避免可见性、有序性问题。是还不足以完全解决线程安全问题。解决线程安全问题的核心方案还是互斥。
实现互斥的核心就是:锁,Java 语言里 synchronized、SDK 里的各种 Lock 都能解决互斥问题。虽说锁解决了互斥性的问题,但是确带来了其他问题,例如死锁等
2.并发编程的实质:操作系统
想学好并发编程,可以深入了解下操作系统的底层的管程模型,信号量等
管程作为一种解决并发问题的模型,是继信号量模型之后的一项重大创新,它与信号量在逻辑上是等价的(可以用管程实现信号量,也可以用信号量实现管程),但是相比之下管程更易用。而且,很多编程语言都支持管程,搞懂管程,对学习其他很多语言的并发编程有很大帮助
实际上 synchronized、wait()、notify() 不过是操作系统领域里管程模型的一种实现而已,Java SDK 并发包里的条件变量 Condition 也是管程里的概念