一、Lock接口
Lock接口声明了手动获取锁和释放锁的方法,Lock接口具有锁的可操作性,可中断获取以及超时获取锁等多种同步特性。Lock接口源码如下所示:
public interface Lock {
void lock();
void lockInterruptibly() throws InterruptedException;
boolean tryLock();
boolean tryLock(long var1, TimeUnit var3) throws InterruptedException;
void unlock();
Condition newCondition();
}
lock方法会忽略中断请求,继续获取锁直到成功;而lockInterruptibly则直接抛出中断异常来立即响应中断,由上层调用者处理中断。以ReentrantLock为例,ReentrantLock部分源码如下所示:
public void lockInterruptibly() throws InterruptedException {
sync.acquireInterruptibly(1);
}
public final void acquireInterruptibly(int arg)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
if (!tryAcquire(arg))
doAcquireInterruptibly(arg);
}
结合ReentrantLock可重入锁测试 lock.lockInterruptibly()方法,当线程被中断时,直接抛出InterruptedException异常。
public class Test implements Runnable {
private Lock lock = new ReentrantLock();
private int count = 0;
public void update() {
this.count++;
System.out.println(String.valueOf(count) + Thread.currentThread());
}
@Override
public void run() {
// try {
// lock.lock();
// System.out.println("I am sleeping!" + Thread.currentThread());
// this.update();
//
// System.out.println("hello world");
// } finally {
// lock.unlock();
// }
try {
lock.lockInterruptibly();
System.out.println("Thread info:" + Thread.currentThread());
this.update();
} catch (InterruptedException e) {
System.out.println("Get InterruptedException!");
} finally {
lock.unlock();
}
}
public static void main(String[] args) {
Test test = new Test();
Thread t1 = new Thread(test);
t1.start();
t1.interrupt(); // 抛出nterruptedException异常
}
}
二、ReentrantLock(可重入锁)
支持重进入的锁,它表示该锁能够支持一个线程对资源的重复加锁(即允许一个线程多次获取同一个锁),分为公平锁和非公平锁(默认)。ReentrantLock通过组合自定义同步器实现锁的获取与释放,部分源码如下所示:
//非公平锁获取锁
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
if (compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
//释放锁
protected final boolean tryRelease(int releases) {
int c = getState() - releases;
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
boolean free = false;
if (c == 0) {
free = true;
setExclusiveOwnerThread(null);
}
setState(c);
return free;
}
公平锁保证了锁的获取按照FIFO原则,代价是进行大量的线程切换。非公平锁可能会造成线程饥饿,但线程切换少,保证了更大的吞吐量。
ReentrantLock具体实例如下所示:
public class LockTest implements Runnable{
private Lock lock = new ReentrantLock();
public void update(){
this.count++;
System.out.println(count);
}
@Override
public void run() {
lock.lock();
try{
this.update();
} finally {
lock.unlock();
}
}
public static void main(String[] args){
LockTest test = new LockTest();
for(int i = 0; i< 10; i++){
new Thread(test).start();
}
}
}
三、 ReadWriteLock接口
读写锁在同一时刻可以允许多个线程读线程访问,但是在写线程访问时,所有的读线程和其他写线程均被阻塞。读写锁接口定义了只读锁和写锁,其源码如下所示:
public interface ReadWriteLock {
Lock readLock();
Lock writeLock();
}
锁降级:从写锁变成读锁;锁升级(不支持):从读锁变成写锁。
四、ReentrantReadWriteLock(读写锁)
读写锁支持非公平(默认)和公平的锁获取方式;支持锁的重进入;支持锁降级。具体实例如下所示:
public class Test implements Runnable{
private ReadWriteLock lock = new ReentrantReadWriteLock();
private Lock readLock = lock.readLock();
private Lock writeLock = lock.writeLock();
private Boolean flag;
private int count = 0;
public Test(boolean flag){
this.flag = flag;
}
public void readFile(){
readLock.lock();
try {
System.out.println(Thread.currentThread() + ":正在进行读操作!");
int res = this.count;
System.out.println(Thread.currentThread() + ":读操作完毕,读取的值为:"+res+"!");
}
finally {
readLock.unlock();
}
}
public void writeFile(){
writeLock.lock();
try {
System.out.println(Thread.currentThread() + ":正在进行写操作!");
this.count++;
System.out.println(Thread.currentThread() + ":写操作完毕,最新值为:"+this.count+"!");
}finally {
writeLock.unlock();
}
}
@Override
public void run() {
if (flag){
this.writeFile();
}
else {
this.readFile();
}
}
public static void main(String[] args) {
boolean flag = new Random().nextInt(10) > 5 ?true:false;
Test test = new Test(flag);
for (int i=0;i< 10;i++){
new Thread(test).start();
}
}
}
锁降级实例如下所示:
public void writeFile(){
writeLock.lock();
try {
System.out.println(Thread.currentThread() + ":正在进行写操作!");
this.count++;
System.out.println(Thread.currentThread() + ":写操作完毕,最新值为:"+this.count+"!");
readLock.lock();
System.out.println(Thread.currentThread() + ":获取到读锁!");
int res = this.count;
System.out.println(Thread.currentThread() + ":读操作完毕,读取的值为:"+res+"!");
}finally {
writeLock.unlock();
}
try {
}finally {
readLock.unlock();
}
}
网友评论