乐观锁
乐观锁(Optimistic Locking)是一种采取宽松加锁机制的锁。顾名思义,乐观锁保持的是一种乐观思想,它会倾向于不会发生并发写操作,所以在读取时它并不会加锁。但是,在我们进行写入操作时,他会进行判断,判断是否对数据进行了修改。在Java中,常见的乐观锁比如ReadWriteLock、StampLock。
悲观锁
悲观锁(Pressmistic Locking)相对于乐观锁而言保持悲观思想,它会消极的认为很可能会发生并发写的操作,所以在持有数据时会锁住数据,在其他线程申请资源时就会阻塞,等待当前锁的释放,悲观锁具有强烈的独占性和排他性。在Java中,常见的悲观锁比如ReentrantLock,synchronized。
死锁
死锁是一种现象,当多个线程在运行时,都需要获取对方所占有的锁时,便会进入无限等待,这就是死锁。
//模拟死锁
public class DeadLock {
public static void main(String[] args) {
DLock dLock = new DLock();
Thread t1 = new Thread(()->dLock.add());
Thread t2 = new Thread(()->dLock.dec());
t1.start();
t2.start();
}
}
class DLock{
private static final Object lockA = new Object();
private static final Object lockB = new Object();
public void add(){
synchronized (lockA){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
synchronized (lockB){
System.out.println("执行A线程");
}
}
}
public void dec(){
synchronized (lockB){
synchronized (lockA){
System.out.println("执行B线程");
}
}
}
发生死锁的必要条件
资源互斥:资源之间有排他性,只允许一个线程占有资源;
不可剥夺:占有资源时,只能通过线程主动释放资源,其他线程才能获得资源;
请求等待:当线程因为请求资源而阻塞的时候,对方线程占有资源而不释放;
循环等待:双方都在等待对方释放资源;
如何检查是否发生死锁
我们可以在程序运行时打开命令台:
键入:jps -l
可以查看当前的Java进程的进程号
键入:jstack [进程号]
可以查看当前进程中是否存在死锁
如何避免死锁
避免出现一个线程占有多个锁。
线程申请锁的顺序应该保持一致。
采用信号量。