面试问道java中有哪些常见的锁,总结一下
乐观锁/悲观锁
乐观锁与悲观锁不是指具体的什么类型的锁,而是指看待并发同步的角度。
悲观锁认为对于同一个数据的并发操作,一定是会发生修改的,哪怕没有修改,也会认为修改。因此对于同一个数据的并发操作,悲观锁采取加锁的形式。悲观的认为,不加锁的并发操作一定会出问题。
乐观锁则认为对于同一个数据的并发操作,是不会发生修改的。在更新数据的时候,会采用尝试更新,不断重新的方式更新数据。乐观的认为,不加锁的并发操作是没有事情的。
自旋锁/自适应自旋锁
自旋锁(spinlock):是指当一个线程在获取锁的时候,如果锁已经被其它线程获取,那么该线程将循环等待,然后不断的判断锁是否能够被成功获取,直到获取到锁才会退出循环。自旋锁尽可能的减少线程的阻塞,适用于锁的竞争不激烈,且占用锁时间非常短的代码块来说性能能大幅度的提升,因为自旋的消耗会小于线程阻塞挂起再唤醒的操作的消耗
自适应自旋锁 :对于自适应自旋锁来说,自旋的次数就不会再受到限制,而是根据同一个锁上的自旋时间以及锁的拥有者状态来决定。对于同一个锁对象上,自旋刚刚成功,并且持有锁的线程正在运行,此时虚拟机就会认为这次的自旋也会成功。若是对于某一个锁来说,自旋很少成功,那么在以后要获取这个锁时候,就会省略掉自旋的过程,以避免浪费处理器资源。
公平锁/非公平锁:
公平锁是指多个线程按照申请锁的顺序来获取锁。
非公平锁是指多个线程获取锁的顺序并不是按照申请锁的顺序,有可能后申请的线程比先申请的线程优先获取锁。有可能,会造成优先级反转或者饥饿现象。
可重入锁/不可重入锁:
可重入锁 :又名递归锁,是指在同一个线程在外层方法获取锁的时候,在进入内层方法会自动获取锁。
// 此处用代码演示了可重入锁的代码层意思
synchronized void setA() throws Exception{
Thread.sleep(1000);
setB(); // 因为获取了setA()的锁(即获取了方法外层的锁)、此时调用setB()将会自动获取setB()的锁,如果不自动获取的话方法B将不会执行
}
synchronized void setB() throws Exception{
Thread.sleep(1000);
}
不可重入锁 :不可递归,递归就会发生死锁,因为外层方法获取锁后,进入内层方法也需要锁,这时外层方法的锁没有释放,内层永远都获取不了这把锁。
独享锁/共享锁:
独享锁是指该锁一次只能被一个线程所持有。
共享锁是指该锁可被多个线程所持有。