锁
synchronized与java.util.concurrent.locks.Lock的相同之处和不同之处:
主要相同点:Lock能完成synchronized所实现的所有功能;
主要不同点:Lock有比synchronized更精确的线程语义和更好的功能。synchronized会自动释放锁,而Lock一定要求程序员手动释放,并必须在finally语句中进行释放;
Java中如何确保N个线程可以访问N个资源,但同时有不导致死锁?
使用多线程时,一种非常简单的避免死锁的方式就是:指定获取锁的顺序,并强制线程按照获取的顺序进行获取锁。如果所有线程都按照同样的顺序进行加锁和释放锁,就不会出现死锁现象。
预防死锁,预先破坏死锁的四个条件。互斥不可破坏,所以有以下三个方法:
破坏请求和保持条件,进程必须要等所有要请求的资源都空闲时才能申请资源,这种方法会使资源浪费严重(有些资源可能只在运行初期或结束时使用,甚至还不使用)。允许进程获取初期所需的资源后,便开始运行,运行过程中逐步释放自己所占有的资源空间,比如有一个进程的任务是将数据复制到磁盘中并进行打印,前期只需要获得磁盘中的资源而不需要获得打印机的资源,待复制完成后在释放掉磁盘中的资源。这种方法比第一种方法好,会使资源利用率上升。
破坏不可抢占条件,,这种方法代价过大,实现复杂。
破坏循环等待条件,对各进程请求资源的顺序做出一个规定,避免相互等待,这种方法相比前两种对资源的利用率都高,但是前期要为设备进行排序,新设备加入会有一个问题,其次对用户编程也有限制。
死锁
两个线程或两个以上的线程都在等待 对方执行完毕才能继续往下执行的同时会出现死锁现象。结果就是这些线程都处于无限等待中。
锁与同步的区别
-
用法有所不同
synchronized既可以用在方法上,也可以用在一段代码上,而lock需要显示指定起始位置和终止位置。
synchronized时托管给JVM进行执行的,lock的锁定至通过代码实现的,它有比synchronized更精确的线程语义。
-
性能上有所不同
lock的实现类RenntrantLock,不仅仅有和synchronized相同的并发性和内存语义,还多了超时的获取锁,定时锁,等候和中断锁等。
在竞争不太激烈时,synchronized的性能要比RenntrantLock优;竞争激烈的情况下synchronized的性能会下降的特别快,而RenntrantLock则基本不变。
-
锁机制不同
synchronized获取锁和释放锁的方式都在块结构中,当获取多个锁时,必须相反的顺序进行释放,并且是自动解锁的;而lock则需要开发人员进行手动释放,并且必须在finally中进行释放,否则会引起死锁现象。
synchronized的重入现象
每个锁都会关联一个线程的持有者和一个计数器。当计数器为0时表示该锁没有被任何线程持有,那么任何线程都有可能获取该锁而调用其中的方法。当一个线程请求成功后,JVM就会记下持有锁的线程,并将关联的计数器设为1.此时其他线程就不能对该锁进行获取,进行等待。而该持有锁的线程如果再次请求这个锁,就可再次拿到这个锁,通知计数器就会递增。当线程退出一个同步块时,计数器就会递减,如果计数器为0时就会释放该锁。