作者:刘宇
CSDN博客地址:https://blog.csdn.net/liuyu973971883
有部分资料参考,如有侵权,请联系删除。如有不正确的地方,烦请指正,谢谢。
重入锁ReentrantLock 相对来说是synchronized、Object.wait()和Object.notify()方法的替代品(或者说是增强版),在JDK5.0的早期版本,重入锁的性能远远好于synchronized,但从JDK6.0开始,JDK在synchronized上做了大量的优化,使得两者的性能差距并不大。但ReentrantLock也有一些synchronized没法实现的特性。
好处:
属性:
Lock是Java中锁的核心接口,提供一系列的基础函数
//获取锁,该方法会一直等到获取到锁为止,不可被打断
void lock();
//获取锁,可被打断
void lockInterruptibly() throws InterruptedException;
//立即返回结果,会尝试获取锁,如果拿到则返回true,反之false
boolean tryLock();
//在一定时间内尝试获取锁,如果拿到则返回true,反之false。可被中断
boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
//释放锁
boolean unlock();
注:关于Condition在我后面一篇的博客中有介绍到
//返回这个锁的Condition
Condition newCondition();
ReentrantLock()
ReentrantLock(boolean fair)
//获取当前被哪个线程获取
Thread getOwner()
//锁是否被当前线程获取到
boolean isHeldByCurrentThread()
//判断锁是否被别的线程抢走
boolean isLocked()
//判断是否公平
boolean isFair()
//判断是否有线程处于等待中
boolean hasQueuedThreads()
//判断指定线程是否处于等待中
boolean hasQueuedThread(Thread thread)
//获取有多少线程处于等待中
int getQueueLength()
//获取调用该方法的线程获取锁的次数,因为可重入锁是可以再次获取该对象锁的
int getHoldCount()
//获取等待队列中的所有线程
Collection<Thread> getQueuedThreads()
//根据Condition判断是否有等待线程,只能在当前线程被lock时候使用,否则就会抛出IllegalMonitorStateException异常
boolean hasWaiters(Condition condition)
//根据Condition获取等待队列的大小,只能在当前线程被lock时候使用,否则就会抛出IllegalMonitorStateException异常
int getWaitQueueLength(Condition condition)
注:由于许多方法都和ReentrantLock中的方法类似,这边就简单介绍几个,其他请看源代码
ReentrantReadWriteLock()
ReentrantReadWriteLock(boolean fair)
//返回写锁
ReentrantReadWriteLock.WriteLock writeLock()
//返回读锁
ReentrantReadWriteLock.ReadLock readLock()
//判断是否有线程拥有写锁
boolean isWriteLocked()
//判断当前线程是否拥有写锁
boolean isWriteLockedByCurrentThread()
package com.brycen.concurrency03.lock;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class ReentrantLockExample {
final static Lock lock = new ReentrantLock();
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(()->testUnInterruptReentrantLock());
t1.start();
TimeUnit.MILLISECONDS.sleep(100);
Thread t2 = new Thread(()->testUnInterruptReentrantLock());
t2.start();
TimeUnit.MILLISECONDS.sleep(100);
//测试lock()是否可以中断
t2.interrupt();
System.out.println("main finish");
}
//立即返回锁
public static void testTryLock() {
if(lock.tryLock()) {
try {
System.out.println(Thread.currentThread().getName()+" get lock and do some things");
while(true) {
}
} finally {
lock.unlock();
}
} else {
System.out.println(Thread.currentThread().getName()+" not get lock and do some things");
}
}
//可中断的获取锁
public static void testInterruptReentrantLock() {
try {
//lockInterruptibly()是可中断的
try {
lock.lockInterruptibly();
System.out.println(Thread.currentThread().getName()+" get lock and do some things");
while(true) {
}
} catch (InterruptedException e) {
e.printStackTrace();
}
} finally {
lock.unlock();
}
}
//不可中断的获取锁
public static void testUnInterruptReentrantLock() {
try {
//lock()是不可中断的
lock.lock();
System.out.println(Thread.currentThread().getName()+" get lock and do some things");
while(true) {
}
} finally {
lock.unlock();
}
}
}
testUnInterruptReentrantLock的运行结果:
Thread-0 get lock and do some things
main finish
testInterruptReentrantLock的运行结果:
Thread-0 get lock and do some things
main finish
java.lang.InterruptedException
at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireInterruptibly(AbstractQueuedSynchronizer.java:898)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireInterruptibly(AbstractQueuedSynchronizer.java:1222)
at java.util.concurrent.locks.ReentrantLock.lockInterruptibly(ReentrantLock.java:335)
at com.brycen.concurrency03.lock.ReentrantLockExample.testInterruptReentrantLock(ReentrantLockExample.java:46)
at com.brycen.concurrency03.lock.ReentrantLockExample.lambda$1(ReentrantLockExample.java:15)
at java.lang.Thread.run(Thread.java:745)
Exception in thread "Thread-1" java.lang.IllegalMonitorStateException
at java.util.concurrent.locks.ReentrantLock$Sync.tryRelease(ReentrantLock.java:151)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.release(AbstractQueuedSynchronizer.java:1261)
at java.util.concurrent.locks.ReentrantLock.unlock(ReentrantLock.java:457)
at com.brycen.concurrency03.lock.ReentrantLockExample.testInterruptReentrantLock(ReentrantLockExample.java:55)
at com.brycen.concurrency03.lock.ReentrantLockExample.lambda$1(ReentrantLockExample.java:15)
at java.lang.Thread.run(Thread.java:745)
testTryLock的运行结果:
Thread-0 get lock and do some things
Thread-1 not get lock and do some things
main finish
package com.brycen.concurrency03.lock;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
public class ReentrantLockExample2 {
final static ReentrantLock reentrantLock = new ReentrantLock();
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(()->testReentrantLock());
t1.start();
TimeUnit.MILLISECONDS.sleep(100);
Thread t2 = new Thread(()->testReentrantLock());
t2.start();
TimeUnit.MILLISECONDS.sleep(100);
System.out.println("当前等待队列的线程数:"+reentrantLock.getQueueLength());
System.out.println("是否有线程处于等待状态:"+reentrantLock.hasQueuedThreads());
System.out.println("t1线程是否处于等待状态:"+reentrantLock.hasQueuedThread(t1));
System.out.println("t2线程是否处于等待状态:"+reentrantLock.hasQueuedThread(t2));
System.out.println("锁是否被其他线程获取到:"+reentrantLock.isLocked());
}
//额外方法测试
public static void testReentrantLock() {
try {
reentrantLock.lock();
//获取当前线程获取锁的次数
System.out.println(Thread.currentThread().getName()+" 获取锁次数: "+reentrantLock.getHoldCount());
System.out.println(Thread.currentThread().getName()+" get lock and do some things");
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
reentrantLock.unlock();
}
}
}
运行结果:
Thread-0 获取锁次数: 1
Thread-0 get lock and do some things
当前等待队列的线程数:1
是否有线程处于等待状态:true
t1线程是否处于等待状态:false
t2线程是否处于等待状态:true
锁是否被其他线程获取到:true
Thread-1 获取锁次数: 1
Thread-1 get lock and do some things
package com.brycen.concurrency03.lock;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class ReentrantReadWriteLockExample {
final static ReentrantReadWriteLock reentrantReadWriteLock = new ReentrantReadWriteLock();
final static Lock writeLock = reentrantReadWriteLock.writeLock();
final static Lock readLock = reentrantReadWriteLock.readLock();
static List<Long> list = new ArrayList<Long>();
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(()->write());
t1.start();
//休眠100毫秒,确保线程t1先启动
TimeUnit.MILLISECONDS.sleep(100);
Thread t2 = new Thread(()->read());
t2.start();
}
public static void write() {
try {
writeLock.lock();
System.out.println(Thread.currentThread().getName()+" start writing");
//休眠5秒模拟写操作
TimeUnit.SECONDS.sleep(5);
list.add(System.currentTimeMillis());
System.out.println(Thread.currentThread().getName()+" finish writing");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
writeLock.unlock();
}
}
public static void read() {
try {
readLock.lock();
System.out.println(Thread.currentThread().getName()+" start reading");
//休眠5秒模拟读操作
TimeUnit.SECONDS.sleep(5);
list.forEach((i)->{System.out.println(i);});
System.out.println(Thread.currentThread().getName()+" finish reading");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
readLock.unlock();
}
}
}
运行结果:
Thread-0 start writing
Thread-0 finish writing
Thread-1 start reading
1596550630927
Thread-1 finish reading
package com.brycen.concurrency03.lock;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class ReentrantReadWriteLockExample {
final static ReentrantReadWriteLock reentrantReadWriteLock = new ReentrantReadWriteLock();
final static Lock writeLock = reentrantReadWriteLock.writeLock();
final static Lock readLock = reentrantReadWriteLock.readLock();
static List<Long> list = new ArrayList<Long>();
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(()->read());
t1.start();
//休眠100毫秒,确保线程t1先启动
TimeUnit.MILLISECONDS.sleep(100);
Thread t2 = new Thread(()->read());
t2.start();
}
public static void write() {
try {
writeLock.lock();
System.out.println(Thread.currentThread().getName()+" start writing");
//休眠5秒模拟写操作
TimeUnit.SECONDS.sleep(5);
list.add(System.currentTimeMillis());
System.out.println(Thread.currentThread().getName()+" finish writing");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
writeLock.unlock();
}
}
public static void read() {
try {
readLock.lock();
System.out.println(Thread.currentThread().getName()+" start reading");
//休眠5秒模拟读操作
TimeUnit.SECONDS.sleep(5);
list.forEach((i)->{System.out.println(i);});
System.out.println(Thread.currentThread().getName()+" finish reading");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
readLock.unlock();
}
}
}
运行结果:
Thread-0 start reading
Thread-1 start reading
Thread-0 finish reading
Thread-1 finish reading