锁的优化
Lock没有引入锁的升级这个概念,只有普通的自旋和偏向锁 synchronized 拥有锁的升级,如自旋锁、适应性自旋锁、锁消除、锁粗化、偏向锁、轻量级锁 等技术来减少锁操作的开销。并且还会随着竞争的激烈而逐渐升级
可中断
synchronized 是不可以被中断的,但Lock是可以中断它的,Lock中断的代码见下方:
代码语言:javascript复制package com.example.demo;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* 使用ReentrantLock还可以调用lockInterruptibly方法,可以对线程interrupt方法做出响应,
* 在一个线程等待锁的过程中,可以被打断
*/
public class 中断锁 {
public static void main(String[] args) {
Lock lock = new ReentrantLock();
Thread t1 = new Thread(() -> {
try {
lock.lock();
System.out.println("t1 start");
TimeUnit.SECONDS.sleep(5000);
System.out.println("t1 end");
} catch (InterruptedException e) {
System.out.println("t1 interrupted!");
} finally {
lock.unlock();
}
});
t1.start();
Thread t2 = new Thread(() -> {
try {
//lock.lock();
lock.lockInterruptibly(); //可以对interrupt()方法做出响应
System.out.println("t2 start");
TimeUnit.SECONDS.sleep(5000);
System.out.println("t2 end");
} catch (InterruptedException e) {
System.out.println("t2 interrupted!");
} finally {
lock.unlock();
}
});
t2.start();
t1.interrupt(); //打断线程1的等待,无法打断,因为线程1是.lock()方法
t2.interrupt(); //打断线程2的等待,可以打断,因为线程2是.lockInterruptibly()方法
}
}
公平锁
Lock支持公平锁,synchronized 不支持公平锁
Lock支持更多场景
ReentrantReadWriteLock:可以对于读或者写进行自定义的锁
private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
private final Lock r = rwl.readLock(); //读锁
private final Lock w = rwl.writeLock(); //写锁
synchronized 锁只能同时被一个线程拥有,但是 Lock 锁没有这个限制
例如在读写锁中的读锁,是可以同时被多个线程持有的,可是 synchronized 做不到
应该选择synchronized还是应该选择Lock?
- 如果能不用最好既不使用 Lock 也不使用 synchronized。因为在许多情况下你可以使用 java.util.concurrent 包中的机制,它会为你处理所有的加锁和解锁操作,也就是推荐优先使用工具类来加解锁
- 如果 synchronized 关键字适合你的程序, 那么请尽量使用它,这样可以减少编写代码的数量,减少出错的概率。因为一旦忘记在 finally 里 unlock,代码可能会出很大的问题,而使用 synchronized 更安全
- 如果特别需要 Lock 的特殊功能,比如尝试获取锁、可中断、超时功能等,才使用 Lock