Java8 Lock锁基本使用
什么是Lock锁?
Lock锁提供了的比synchronized关键字更加灵活的锁操作,是代码层面的锁操作。
为什么要使用Lock锁?
Lock锁和synchronized关键字的对比
synchronized关键字
获取锁无超时时间,未获取到则阻塞等待(占用cpu资源),且无法被中断非阻塞,
共享锁不支持
释放锁必须在当前代码块中,因为synchronized是以{}来锁住共享资源的
Lock锁
可以被中断,未获取到则排队,中断,可以自定义超时时间
读写锁ReadWriteLock支持
可以在任意位置释放锁(其他方法或者其他类)
概念普及
公平锁:保证每个线程都能获取到锁(排队先进来的先获取到锁),能够避免线程饥饿
非公平锁:谁抢到就是谁的,抢不到就排队
悲观锁:每次更新和读取都加锁,对于读多写少这种场景不利,适用于于写多读少的场景
乐观锁:更新失败则重试,适用一个标记位来控制,适用于多读的场景。
可重入锁:同一线程多次进入无需重新获取锁
共享锁(读锁):一个锁可以同时被多个线程拥有,ReentrantReadWriteLock的读锁为共享锁,写锁为排他锁
排他锁(写锁):独占锁,一个锁在某一时刻只能被一个线程占有,其它线程必须等待锁被释放之后才可能获取到锁,ReentrantLock就是排他锁。
public class LockTest {
// 这个必须放在成员变量或者作为方法参数进行传递。具体原因见后面代码分析
private final Lock lock = new ReentrantLock();
// 共享资源a
private int a = 0;
public static void main(String[] args) throws InterruptedException {
LockTest lockTest = new LockTest();
for (int i = 0; i < 10; ++i) {
// 模拟10个线程对 a进行++
new Thread(() -> {
for (int j = 0; j < 10000; ++j) {
lockTest.testLock();
}
}).start();
}
// 防止因为主线程结束,导致程序运行失败
Thread.sleep(5000);
System.out.println(lockTest.a);
}
public void testLock() {
try {
// 这块加锁也应该放到for循环外面。放里面会有性能问题。每+1就释放锁,
// 正常用该是+n然后等待cpu调度,然后释放锁
lock.lock();
++a;
} finally {
lock.unlock();
}
}
}
领取专属 10元无门槛券
私享最新 技术干货