? ? ? ? 在多线程并发环境中,当某段代码被多个线程并发执行会导致数据不一致的情况出现时,我们就需要对这段代码加锁以保证线程安全了,我们可以对它施加互斥锁或者自旋锁,具体根据这段代码的执行耗时来定。
? ? ? ? 互斥锁的特点是:一把互斥锁在同一时刻只能被一个线程所持有,当互斥锁被某个线程所持有时,其他来尝试获取这把锁的线程将获取失败,由运行状态切换到阻塞状态,阻塞在这把锁的外面等待,等待这把锁被释放之后重新进入到锁的竞争当中。因为获取锁失败的线程进入了阻塞状态,所以它释放了自己所占用的cpu内核,cpu内核被释放之后就可以去执行其它的操作了。
? ? ? ? 自旋锁的特点是:一把自旋锁在同一时刻只能被一个线程所持有,当自旋锁被某个线程所持有时,其它来尝试获取这把锁的线程将获取失败,但获取失败后线程并不会进入阻塞状态,它依然是运行状态,依然占用着cpu内核,在这把锁的外部执行自旋,并不断地重试获取锁。
? ? ? ? 自旋锁只适用于锁的持有时间比较短的业务场景,因为线程在自旋锁获取失败后仍然占用着cpu,如果在锁持有时间长的业务场景中使用自旋锁,会导致cpu被长时间用来进行自旋而降低cpu的使用效率。
? ? ? ? 互斥锁适用于锁持有时间比较长的业务场景,以便让竞争锁失败的线程切换到阻塞状态释放cpu的执行权,让cpu去执行其它操作,提高cpu的执行效率。如果在锁的持有时间比较短的业务场景中使用互斥锁,会导致竞争锁失败的线程频繁地进行线程状态的切换,而线程状态切换是非常消耗cpu的一种操作,会降低执行性能。
? ? ? ? 综上也能得出一个结论:线程不适合做频繁的状态切换操作;CPU内核也不适合将大量的时间消耗在让线程做自旋上。