==可重入锁==:当一个线程获取一个对象上的锁的时候,会自动获取该对象的其他锁,而其他线程不可获取该对象的任何锁(一般都是可重复锁)
可重入锁的代码示例:
public class Lock{
boolean isLocked = false;
Thread lockedBy = null;
int lockedCount = 0;
public synchronized void lock()
throws InterruptedException{
Thread thread = Thread.currentThread();
while(isLocked && lockedBy != thread){
wait();
}
isLocked = true;
lockedCount++;
lockedBy = thread;
}
public synchronized void unlock(){
if(Thread.currentThread() == this.lockedBy){
lockedCount--;
if(lockedCount == 0){
isLocked = false;
notify();
}
}
}
}
==不可重入锁==:当一个线程获取一个对象上外层方法的锁的时候,如果接下来的方法又需要获取另一个锁,则需要先等待锁释放才能获取下一个
不可重入锁的代码示例:
public class Lock{
private boolean isLocked = false;
public synchronized void lock() throws InterruptedException{
while(isLocked){
wait();
}
isLocked = true;
}
public synchronized void unlock(){
isLocked = false;
notify();
}
}
如果再同一个方法里,连续调用两次 lock() 方法,会发生死锁。
==死锁==: 多个进程在运行过程之中因争夺资源而造成的一种僵局
==读锁==: 可以共享,多个线程可以同时拥有读锁
==写锁==: 只能只有一个线程拥有,而且获取写锁的时候其他线程都已经释放了读锁,该线程获取写锁之后,其他线程不能再获取读锁。简单的说就是写锁是排他锁,读锁是共享锁。Java中实现读写锁的类是:ReentrantReadWriteLock;
保证一定能读到最新数据,修改期间,写锁是一个排它锁(互斥锁、独享锁),读锁是一个共享锁
写锁没释放读锁必须等待
读 + 读 :相当于无锁,并发读,只会在Redis中记录好,所有当前的读锁。他们都会同时加锁成功
写 + 读 :必须等待写锁释放
写 + 写 :阻塞方式
读 + 写 :有读锁。写也需要等待
只要有读或者写的存都必须等待
==自旋锁==:是指当一个线程在获取锁的时候,如果锁已经被其它线程获取,那么该线程将循环等待,然后不断的判断锁是否能够被成功获取,直到获取到锁才会退出循环。
==共享锁==:用于不更改数据的、只读、查询等操作,如 SELECT 语句,读文件等。获取共享锁的事务只能读数据,不能修改数据。
==排它锁=:用于数据的修改,比如 INSERT,UPDATE,或 DELETE,同一资源在同一时间只能有一个用户获得排它锁。
==闭锁==:闭锁是一种同步工具类,可以延迟线程的进度直到其到达终止状态;
==信号量==:和自旋锁一样,信号量也是保护临界资源的一种有用方法。信号量只有当得到信号量时,进程或者线程才能够进入临界区,执行临界代码。
信号量与自旋锁的最大不同点在于,当一个进程试图去获取一个已经锁定的信号量时,该进程不会像自旋锁一样在自旋忙等待,而是会将自身加入一个等待队列中去睡眠,直到其他进程释放信号量后,处于等待队列中的进程才会被唤醒。当进程唤醒之后,就立刻重新从睡眠的地方开始执行,又一次试图获得信号量,当获得信号量后,程序继续执行。
所以,从信号量的原理上来说,没有获得信号量的函数可能睡眠。这就要求只有能够睡眠的进程才能够使用信号量,不能睡眠的进程不能使用信号量。例如中断处理程序中,由于中断需要立刻完成,所以不能睡眠,也就是说在中断处理程序中不能使用信号量。