相同点:Lock能完成synchronized所实现的所有功能。 不同点:Lock有比synchronized更精确的线程语义和更好的性能。 synchronized会自动释放锁,而Lock一点要求人工释放,而且必须再finally语句中释放。
使用多线程的时候,一种非常简单的避免死锁的方式就是:指定获取锁的顺序,并强制线程按照指定的顺序获取锁。因此,如果所有的线程都是以同样的顺序加锁和释放锁,就不会出现死锁了 预防死锁,预先破坏产生死锁的四个条件。互斥不可能破坏。 1.破坏请求和保持条件,进程必须等所有要请求的资源都空闲时才能申请资源,这种方法会使资源严重浪费(有些资源可能仅在运行初期或结束时才使用,甚至根本不使用)。允许进程获取初期所需资源后,便开始运行,运行过程中逐步释放自己占有的资源,比如有一个进程的任务时把数据复制到磁盘中再打印,前期只需获得磁盘资源而不需要获得打印机资源,待复制完毕后再释放掉磁盘资源。这样会使资源的利用率上升。 2.破坏不可抢占条件,代价大,实现复杂。 3.破坏循环等待条件:对进程请求资源的顺序做一个规定,避免相互等待。这种方法对资源的利用率比前两种都高,但是前期要为设备指定序号,新设备加入会有一个问题,其次对用户编程也有限制。
两个线程或两个以上线程都在等待对方执行完毕才能继续往下执行的时候就发生了死锁。结果就是这些线程都陷入了无线的等待中。 例如,线程1锁住了A,然后尝试对B进行加锁,同时线程2已经锁住了B,接着尝试对A进行加锁,这时死锁就发生了。线程1永远得不到B,线程2永远得不到线程A,并且它们永远也不会知道发生了这样的事情。为了得到彼此的对象,将永远阻塞下去。这就是死锁。
一、用法上: 1.synchronized既可以加在方法上,也可以加在特定的代码块上,而Lock需要显示的指定起始位置和终止位置。 2.synchronized是托管给JVM执行的,lock的锁定是通过代码实现的,他有比synchronized更精确的线程语义。 二、性能上的不同: lock接口的实现类ReentrantLock,不仅具有和synchronized相同的并发性和内存语义,还多了超时锁、定时锁、等候和中断锁。在竞争不是很激烈的情况下,synchronized的性能优于ReentrantLock,竞争激烈的情况下synchronized性能会下降的非常快,而ReentrantLock则基本不变。 三、锁机制不同: synchronized获取锁和释放锁的方式都是在块结构中,当获取多个锁时,必须以相反的顺序释放,并且是自动解锁。而Lock则需要开发人员手动释放,必须在finally中释放,否则会引起死锁。
每个锁关联一个线程持有者和一个计数器。当计数器为0时表示该锁没有被任何线程持有,那么任何线程都可能获得该锁而调用相应方法。当一个线程请求成功后,JVM会记下持有锁的线程,并将计数器记为1.此时线程请求该锁,则必须等待。而该持有锁的线程如果再次请求这个锁,就可以再次拿到这个锁,同时计数器会递增。当线程退出一个synchronized方法/块时,计数器会递减,如果计数器为0则释放该锁。
如果一个锁是公平的,那么锁的获取顺序就应该符合请求的绝对时间顺序,FIFO。对于非公平锁,只要CAS设置同步状态成功,则表示当前线程获取了锁,而公平锁还需要判断当前节点是否有前驱节点,如果有,则表示有线程比当前线程更早请求获取锁,因此需要等待前驱线程获取并释放锁之后才能继续获取锁。