本文首发地址:https://www.dawnsite.cn/archives/266.html
1.Lock锁概述
从JDK5.0开始,Java提供了更强大的线程同步机制–通过显式定义同步锁对象来实现同步。
java.util.concurrent.locks.Lock接口是控制多个线程对共享资源进行访问的工具。锁提供了对共享资源的独占访问,每次只能有一个线程对Lock对象加锁,线程开始访问共享资源之前应先获得Lock对象。
ReentrantLock(可重入锁)类实现了Lock,它拥有与synchronized相同的并发性和内存语义,在实现线程安全的控制中,比较常用的时ReentrantLock,可以显式加锁、释放锁。
Lock是一个接口,两个直接实现类:ReentrantLock(可重入锁),ReentrantReadWriteLock(读写锁)
语法:
//定义锁
private final ReentrantLock lock = new ReentrantLock();
lock.lock();//加锁
try {
//保证线程安全的代码
}finally {
lock.unlock;//解锁
}
示例:
public class TestLock{
public static void main(String[] args) {
TestLock2 testLock2 = new TestLock2();
new Thread(testLock2).start();
new Thread(testLock2).start();
new Thread(testLock2).start();
}
}
class TestLock2 implements Runnable{
int ticketNums = 10;
//定义lock锁
private final ReentrantLock lock = new ReentrantLock();
@Override
public void run() {
while (true) {
lock.lock();//加锁
try{
if (ticketNums > 0){
try {
Thread.sleep(1000);
System.out.println(ticketNums--);
} catch (InterruptedException e) {
e.printStackTrace();
}
}else{
break;
}
}finally {
lock.unlock();//解锁
}
}
}
}
2. Lock锁的API
修饰符和类型 | 方法 | 描述 |
---|---|---|
void | lock() | 获得锁 |
void | lockInterruptibly() | 获得锁,可中断。举个例子,当两个线程同时通过lock.lockInterruptibly()想获取某个锁时,假若此时线程A获取到了锁,而线程B只有在等待,那么对线程B调用threadB.interrupt()方法能够中断线程B的等待过程。 |
boolean | tryLock() | 锁在空闲的时候才能获取锁(未获得锁不会等待)。举个例子:当两个线程同时通过lock.terLock()想获取某个锁时,假若此时线程A获取到了锁,而线程B不会等待,直接放弃获取锁。 |
boolean | tryLock(Long time, TimeUnit unit) | 如果锁定可用,则此方法立即返回true 如果锁不可用,则当前线程将被禁用以进行线程调度,并且在发生以下三种情况之一之前处于休眠状态: 1.当前线程获取锁 2.其它一些线程中断当前线程 3.等待时间过去了,返回false |
void | unlock() | 释放锁 |
3.synchronized与Lock的对比
-
Lock是显式锁(手动开启和关闭锁,别忘记关闭锁)synchronized是隐式锁,出了作用域自动释放
-
Lock只有代码块锁,synchronized有代码块锁和方法锁
-
使用Lock锁,JVM将花费较少的时间来调度线程,性能更好。并且具有更好的扩展性(提供更多的子类)
-
优先使用顺序:
Lock > 同步代码块(已经进入了方法体,分配了资源) > 同步方法(在方法体之外)