栏目分类:
子分类:
返回
终身学习网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
终身学习网 > IT > 软件开发 > 后端开发 > Java

软构博客5 锁和同步

Java 更新时间:发布时间: 百科书网 趣学号
Lock和synchronized有以下几点不同:

1)Lock是一个接口,而synchronized是Java中的关键字,synchronized是内置的语言实现,synchronized是在JVM层面上实现的,不但可以通过一些监控工具监控synchronized的锁定,而且在代码执行时出现异常,JVM会自动释放锁定,但是使用Lock则不行,lock是通过代码实现的,要保证锁定一定会被释放,就必须将 unLock()放到finally{} 中;

2)synchronized在发生异常时,会自动释放线程占有的锁,因此不会导致死锁现象发生;而Lock在发生异常时,如果没有主动通过unLock()去释放锁,则很可能造成死锁现象,因此使用Lock时需要在finally块中释放锁;

3)Lock可以让等待锁的线程响应中断,线程可以中断去干别的事务,而synchronized却不行,使用synchronized时,等待的线程会一直等待下去,不能够响应中断;

4)通过Lock可以知道有没有成功获取锁,而synchronized却无法办到。

5)Lock可以提高多个线程进行读操作的效率。

同步

并发程序的正确性不应依赖于时间上的意外。

由于并发操作共享可变数据引起的竞争条件是灾难性的错误——难以发现、难以重现、难以调试——我们需要一种方法让共享内存的并发模块相互同步。

锁是一种同步技术。锁是一种抽象,它一次最多允许一个线程拥有它。 持有锁是一个线程告诉其他线程的方式:“我正在处理这个东西,现在不要碰它。”

锁有两种操作:

  • acquire允许线程获得锁的所有权。如果一个线程试图获取另一个线程当前拥有的锁,它会阻塞,直到另一个线程释放锁。此时,它将与任何其他试图获取锁的线程竞争。一次最多一个线程可以拥有锁。

  • release放弃锁的所有权,允许另一个线程获得它的所有权。

使用锁还告诉编译器和处理器您正在同时使用共享内存,因此寄存器和缓存将被刷新到共享存储中。这避免了重新排序的问题,确保锁的所有者始终查看最新数据。

通常,阻塞意味着线程等待(不做进一步的工作)直到事件发生。

如果acquire(l)另一个线程(例如线程 2)持有 lock ,则线程 1 上的一个将阻塞l。它等待的事件是线程 2 执行release(l)。此时,如果线程 1 可以获取l,它将继续运行其代码,并拥有锁的所有权。有可能另一个线程(比如线程 3)也被阻塞了acquire(l)。线程 1 或 3 将获取锁l并继续。release(l)对方会继续阻塞,再次等待。

死锁

正确小心地使用锁时,锁可以防止出现竞速情况。但是另一个问题又冒了出来。因为使用锁需要线程等待(acquire当另一个线程持有锁时,可能会出现两个线程正在等待的情况为了彼此-因此两者都不能取得进展。

假设A和B在我们银行的两个账户之间同时转账。

账户之间的转账需要锁定两个账户,这样资金就不会从系统中消失。A和B各自从各自的“from”帐户获得锁:A获得帐户1的锁,B获得帐户2的锁。现在,每个人都必须获得他们的“to”帐户的锁:所以A在等待B释放account2锁,B在等待A释放account1锁。僵局!A和B被冻结在“致命的拥抱”中,账户被锁定。

死锁当并发模块卡住等待对方执行某项操作时发生。死锁可能涉及两个以上的模块:死锁的信号特征是依赖循环例如,A在等待B,而B在等待C,而C在等待A,他们中的任何一个都不能取得进展。

也可以在不使用任何锁的情况下发生死锁。例如,当消息缓冲区填满时,消息传递系统可能会遇到死锁。如果客户机用请求填满服务器的缓冲区,然后阻碍等待添加另一个请求时,服务器可能会用结果填满客户机的缓冲区,然后自行阻塞。因此,客户机在等待服务器,而服务器在等待客户机,在另一个客户机等待之前,两者都无法取得进展。再次,僵局接踵而至。

转载请注明:文章转载自 www.051e.com
本文地址:http://www.051e.com/it/956696.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 ©2023-2025 051e.com

ICP备案号:京ICP备12030808号