基本的并发概念
并发与并行
-
并发
在单个处理器上采用单核执行多个任务即为并发。
在这种情况下,操作系统的任务调度程序会很快从一个任务切换到另一个任务,因此看起来所有任务都是同时运行的。 -
并行
同一时间在不同的计算机、处理器或处理器核心上同时运行多个任务,就是所谓的“并行”。
同步
在并发中,我们可以将同步定义为一种协调两个或更多任务以获得预期结果的机制。
-
控制同步
当一个任务的开始依赖于另一个任务的结束时,第二个任务不能在第一个任务完成之前开始。 -
数据访问同步
当两个或更多任务访问共享变量时,在任意时间里,只有一个任务可以访问该变量。
并发系统中有不同的同步机制。从理论角度来看,最流行的机制如下:
-
信号量(semaphore)
一种用于控制对一个或多个单位资源进行访问的机制。
它有一个用于存放可用资源数量的变量,并且可以采用两种原子操作来管理该变量的值。
互斥(mutex,mutualexclusion 的简写形式)是一种特殊类型的信号量,它只能取两个值(即资源空闲和资源忙),而且只有将互斥设置为忙的那个进程才可以释放它。
互斥可以通过保护临界段来帮助你避免出现竞争条件。 -
监视器
一种在共享资源之上实现互斥的机制。
它有一个互斥、一个条件变量、两种操作(等待条件和通报条件)。
一旦你通报了该条件,在等待它的任务中只有一个会继续执行。
不可变对象
不可变对象是一种非常特殊的对象。在其初始化后,不能修改其可视状态(其属性值)。
如果想修改一个不可变对象,那么你就必须创建一个新的对象。
不可变对象的主要优点在于它是线程安全的。你可以在并发应用程序中使用它而不会出现任何问题。
不可变对象的一个例子就是 Java 中的 String 类。当你给一个 String 对象赋新值时,会创建一个新的 String 对象。
原子操作和原子变量
原子操作是一种发生在瞬间的操作。
在并发应用程序中,可以通过一个临界段来实现原子操作,以便对整个操作采用同步机制。
原子变量是一种通过原子操作来设置和获取其值的变量。
可以使用某种同步机制来实现一个原子变量,或者也可以使用 CAS 以无锁方式来实现一个原子变量,而这种方式并不需要任何同步机制。
共享内存与消息传递
任务可以通过两种不同的方法来相互通信:
-
共享内存
通常用于在同一台计算机上运行多任务的情况。
任务在读取和写入值的时候使用相同的内存区域。
为了避免出现问题,对该共享内存的访问必须在一个由同步机制保护的临界段内完成。 -
消息传递
通常用于在不同计算机上运行多任务的情形。
当一个任务需要与另一个任务通信时,它会发送一个遵循预定义协议的消息。
如果发送方保持阻塞并等待响应,那么该通信就是同步的;如果发送方在发送消息后继续执行自己的流程,那么该通信就是异步的。