互斥:对于临界资源(区),同时只有一个线程能够访问。
协作:生产者与消费者
经常会用到的几个概念,不同的语言可能有不同的实现,但是概念是一样。
volatile:这个无论JAVA还是C都提供了这么一个关键字。它是指需要内存的透传,CPU不能对它修饰的变量进行缓存,多个线程看到的值,一定是一样的。
Atomic:原子操作,指的一段代码需要作为一个(不能被进一步分割的整体)执行。GCC编译器或者JDK会提供一些原语,比如C的compare_and_swap,Java的AtomicXXX等。
Mutex:互斥量,它代表了一个临界资源。相对于Semaphore,它代表了一个。在某个线程需要用它的时候,需要先获取这个互斥量的锁,然后才能执行,离开临界区的时候要释放这个锁。
Semaphore:信号量,它代表了某些数量有限的公共资源,比如数据库连接池。信号量的值,就是它的个数。每当一个线程获取了这个其中一个资源的时候,信号量减一;当释放某个资源的时候,信号量加一。当信号量为0的时候,那么需要资源的线程就需要进入等待状态。
Wait:等待,一般作用于某个资源。当这个资源可用数目为0的时候,那么就需要陷入暂停,对这个资源进行等待。
Notify:通知,一般作用于某个资源。当释放了这个资源的时候,为了通知给其它的线程,那么就需要Notify一下。这样,等待的某个线程就会获取这个资源并唤醒自己,继续进行。
Lock/Unlock:加锁/解锁,也类似于: 申请资源/释放资源。是成对的操作,作用于Mutex。
Aquire/Release:申请资源/释放资源,是成对的操作。是对Semaphore的操作。
synchronized: JavaSDK的关键字,加锁和解锁的过程自动进行,易于操作,但不够灵活。
对于线程的互斥与协作,我们一般是将它们封装成类,比如线程池、数据库连接池、Provider/Consumer、MessageQueue等等。这样,使用方,就不用太多关注并发/并行的细节,将更多的精力投入到业务中来。
最基础的一个就是锁。对于锁,有很多的名称:轻量级锁,重量级锁,独占锁,共享锁,公平锁,偏向锁,读写锁、重入锁、自旋锁,甚至悲观锁,乐观锁等等。