在开始我们的并发编程前,我们必须预热一下,一些基本概念必须了解。
1. 同步(Synchronous) / 异步(Asynchronous)
同步和异步都指一次方法调用。
同步:方法开始后,调用者必须等到该方法调用结束返回后,才能继续后续的操作。
异步:异步方法有点像发送一个消息传递,开始后方法调用会立即返回,调用者可以马上
进行后续的操作。
(异步方法通常会在主线程外的另一个线程中, 不会阻碍主线程)
2. 并发(Concurrency) / 并行(Parallelism)
我们经常会混淆并发(Concurrency)和并行(Parallelism)。
相同点:它们都表示多个任务一起执行。
不同点:并发(Concurrency)偏重于多个任务交替执行,这些任务彼此之间可能是串行的。
(eg: 一会儿运行任务A, 一会儿又运行任务B, 系统不会不停地在多个任务间进行切换)
并行(Parallelism)才是真正意义上的同时执行。
场景:
如果系统只有一个CPU(单核), 如果我们使用多线程,那么是不可能并行的,因为一个CPU一次只能执行一条指令。
真实的并行只能出现在多个CPU(多核)的系统中。
3. 临界区
它指的是一种公共资源,该资源每次只能有一个线程使用它,一旦它被某个线程所占用,其它线程就必须等待。
4. 阻塞(Block) / 非阻塞(Non-Block)
阻塞和非阻塞用来形容多个线程间的相互影响。
场景:
一个线程占用了临界区资源,其它线程挂起等待,这种情况就是阻塞。
非阻塞是指所有的线程都不断向前执行,没有被挂起。
5. 死锁(DeadLock) / 饥饿(Starvation) / 活锁(LiveLock)
它们都属于线程的活跃性问题。
死锁是一种很严重的问题。
比如几辆车互相挡住了各自的通道,大家都不愿意让出自己的通道,导致死循环。
饥饿是指某个线程因为某些原因无法获得所需要的资源,导致一直无法执行。
这种情况可能是该线程的优先级太低,高优先级的线程不断抢占它需要的资源。
或者是某个线程一直占着关键资源不放,导致其它需要这个资源的线程无法执行。
活锁比较有趣,它指的是线程都主动将资源释放给他人使用,大家把这个资源丢来丢去,没人肯接受。
这样就导致没有一个线程可以同时拿到所有的资源而正常执行。
太谦让也不好!!^_^
6. 原子性(Atomicity)
原子性是指一个操作是不可中断的,该操作一旦执行,就不能被中断,即使在多线程的环境中,也不会被其他线程干扰。