用法
lock使用语法比较固定,由于不能自动释放锁,同时又避免可能异常倒是锁无法释放,所以需要在finally只中对锁进行释放,使用语法模版如下。
使用模版
lock.lock();
try {
// 同步代码块
} catch (Exception e) {
} finally {
lock.unlock();
}
lock用法举例
public class LockTest {
private static final List<String> list = new ArrayList<>();
private static final Lock lock = new ReentrantLock();
private static CountDownLatch latch;
private static Integer counter = 1;
public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(2);
LockTest lockTest = new LockTest();
latch = new CountDownLatch(2);
executor.execute(() -> lockTest.addName());
executor.execute(() -> lockTest.addName());
try {
latch.await();
} catch (InterruptedException e) {
}
System.out.println(list);
executor.shutdownNow();
}
public void addName() {
lock.lock();
try {
/****************************业务代码(开始)****************/
System.out.println(Thread.currentThread().getName()+ "lock");
for(; counter < 10 ; counter++) {
list.add(String.format("%d_%s", counter, Thread.currentThread().getName()));
}
System.out.println(Thread.currentThread().getName()+ "unlock");
/***************************业务代码(结束)*****************/
} catch (Exception e) {
} finally {
lock.unlock();
latch.countDown();
}
}
}
注意点
note: 1)加锁语句lock.lock();后面必须try语句之前;2)lock.unlock()语句必须是finally中第一条语句。不禁问why,只所以这样,在加锁到释放锁之前所有发生的异常都是在try …catch语句中发生的,这两个部分可能发生的异常不影响finally执行。如果在加锁lock.lock()和try之间还可以插入语句,那中间就有可能发生异常,这中间的发生的异常因为没有被捕捉catch,导致程序无法继续执行,finally语句也无法执行。同理,如果lock.unlock()不是finally的第一条语句,那么finally中依然可能发生异常,此时发生的异常也由于没有对应的处理而导致程序无法执行,无法执行解锁语句。
实现原理
synchronized同步机制是依赖JVM实现,Lock主要依赖抽象队列同步器(AbstractQueuedSynchronier,AQS)实现的,AQS是一个双向链表,使用一个整型变量state表示对共享区域的加锁状态,对于每个尝试访问临界区的线程都会被封装成双向链表中的一个节点,主要通过tryacquired获取临界区访问权,通过tryrelease释放临界区访问权。