大家好,我是老七,点个关注吧,将持续更新更多精彩内容!
往期精彩内容请看:
程序员一定要会的并发编程,你了解多少?(1)
程序员一定要会的并发编程,你了解多少?(2)
今天我们来聊聊并发编程中的锁,锁在并发编程中起到了非常关键性的作用,下面我们详细的介绍下:
锁的分类详解:
在并发编程里,锁能够帮我们解决多个线程同时访问共享资源的问题。下面就是关于锁的分类:
- 可重入锁和不可重入锁:
可重入锁就是想象你有一把锁,锁住了一扇房门。如果你已经在房间里,但你想再次锁上门,可重入锁就像是你可以多次转动锁,将门重新锁上,而不会遇到问题。也就是说,你可以多次进入同一个房间,并且在里面可以多次锁门,而只有在最后一次退出时才能完全打开锁。这就是可重入锁的概念。它允许同一个线程多次获得锁,而不会被自己锁住
而不可重入锁就像是一把锁,但如果你已经在房间里并试图再次锁门,它会卡住,不允许你重新锁门,因为锁已经被占用。这意味着一个线程不能在自己已经获得锁的情况下再次获得相同的锁,否则会导致死锁或其他问题。
- 乐观锁和悲观锁:
乐观锁的思想是假定在大多数情况下,共享资源不会被多个线程同时修改。因此,它采用一种轻量级的方式,不会立即阻塞线程,而是先尝试进行操作。当一个线程尝试修改资源时,它会首先检查资源的当前状态,然后尝试进行修改。如果资源在此期间没有被其他线程修改,操作将成功。如果资源已被其他线程修改,它将进行一些处理,例如重新尝试或者抛出异常。
你可以将乐观锁比喻为在超市购物时不排队,而是直接拿起商品,然后去结账。如果商品没有被其他人拿走,你可以成功结账;如果别人已经拿了,你需要重新选择或等待。
悲观锁则是假定共享资源会频繁地被多个线程修改,因此在操作前会立即锁住资源,以确保只有一个线程可以访问资源。悲观锁会导致其他线程在操作资源时被阻塞,直到持有锁的线程释放它。
想象你去银行排队办理业务,每个人必须等待自己的轮次,不能同时进入窗口。这就是悲观锁的概念,它假定会有竞争,因此在访问资源时先锁住,以避免冲突。
- 公平锁和非公平锁:
公平锁的基本思想是按照申请锁的顺序来分配资源。当多个线程请求一个公平锁时,锁会按照它们请求的先后顺序逐个分配资源,即先来先得。这意味着等待时间最长的线程将首先获得锁,确保了资源的均衡分配。
你可以将公平锁比喻为排队买票,每个人按照到达的顺序依次买票,而不会插队。这有助于公平地分配资源,但可能会导致某些线程等待时间较长。
非公平锁没有严格的顺序,它允许新来的线程在任何时刻尝试获取锁,而不管其他线程是否已经在等待。这意味着某些线程可能会频繁地插队并立即获得锁,而其他线程可能需要等待更长的时间。
想象一群人争抢电梯,不一定是按照到达顺序,有时候新来的人可以立即进入电梯,这就是非公平锁的概念,它允许相对较新的请求在前面的请求之前获得锁。
- 互斥锁和共享锁:
互斥锁用于控制对共享资源的独占访问,这意味着一次只允许一个线程获得锁并访问资源,其他线程必须等待直到锁被释放。互斥锁的主要目标是确保在任何给定时间内只有一个线程可以修改共享资源,以避免数据竞争和不一致性。
你可以将互斥锁比喻为一把钥匙,只有一个人可以持有这把钥匙,而其他人必须等待获得钥匙才能进入房间。这确保了资源的排他性访问。
共享锁允许多个线程同时获得锁并访问共享资源,但不允许线程在获得共享锁的同时修改资源。这意味着多个线程可以同时读取共享资源,但只有一个线程可以修改它,以确保数据的一致性。
想象一个图书馆,多个人可以同时借阅同一本书,但只有一个人可以修改书的内容。这就是共享锁的概念,允许多个线程并发读取资源,但在写入时需要排他性。
在并发编程中,我们需要根据实际需求来选择适当的锁类型来管理共享资源的访问。
可重入锁、乐观锁和公平锁等特性可以根据具体情况来选择使用。这意味着你可以根据你的需求,选择支持多次进入的可重入锁,或者使用乐观锁来减少锁的争用,或者使用公平锁来确保资源的公平分配。
同时,我们还需要小心避免一些问题,如死锁,以确保程序既正确运行又高效。在处理多线程同步时,这些都是重要的考虑因素。
在Java中,锁是实现多线程同步的关键工具之一。互斥锁和共享锁是最常见的两种锁类型。
- 互斥锁(Mutex)是一种锁,一次只允许一个线程持有,以确保在任何时刻只有一个线程可以执行被保护的资源或代码段。Java中,你可以使用内置的关键字 synchronized 或 ReentrantLock 来实现互斥锁。这就好比进入一个房间,其他人必须等待你出来才能进去。
- 共享锁 是一种锁,允许多个线程同时持有,也被称为读锁。在Java中,你可以使用 ReentrantReadWriteLock 来实现共享锁。这使多个线程能够同时读取共享资源,但如果有一个线程想要写入,其他线程必须等待,以确保数据一致性。
除了互斥锁和共享锁,Java还提供了其他锁工具和机制,如信号量(Semaphore)、倒计时门闩(CountDownLatch)、循环栅栏(CyclicBarrier)、先行触发器(Exchanger)等。这些工具可以满足不同的同步需求,同时使代码更易于理解和维护。
在选择锁和工具时,我们需要根据具体情况权衡各种因素。如果需要更细粒度的控制,可以选择手动控制的锁,如 ReentrantLock;如果追求更简洁的代码,可以选择内置的锁机制,如 synchronized。但无论如何,都需要谨慎考虑锁的性能和线程调度问题,以避免潜在的问题,如运行慢或死锁。
总之,Java中的锁机制就像是一把关键,用来确保多线程同步任务的安全执行。选择适当的锁和工具可以使我们的代码更加可靠、安全和高效。
今天简单的介绍了下并发编程中锁的概念以及分类,后续我们将来聊聊各种锁的实现原理。
如果各位觉得老七的文章还不错的话,麻烦大家动动小手,
点赞、关注、转发走一波!!
有任何问题可以评论区留言或者私信我,我必将知无不言言无不尽!