1、ReentrantLock介绍
ReentrantLock是一种可重入的共享或排它锁
ReentrantLock内部使用CAS实现,不会像Synchronized引起上下文切换和线程调度
ReentrantLock提供比Synchronized更多的功能ReentrantReadWriteLock与ReentrantLock没有继承关系,实现是相互独立的
2、ReentrantLock排它锁
代码示例
public class TestTest
{
public static void main(String[] args) throws ParseException
{
ReentrantLock reenTrantLock = new ReentrantLock();
int THREAD_NUM = 3;
ExecutorService executorService = Executors.newFixedThreadPool(THREAD_NUM);
for(int i=0;i<THREAD_NUM;i++){
executorService.execute(new TestThread(reenTrantLock));
}
executorService.shutdown();
while(!executorService.isTerminated()){
;
}
System.out.println("----end----");
}
}
class TestThread implements Runnable {
private ReentrantLock innerLock;
public TestThread(ReentrantLock innerLock){
this.innerLock = innerLock;
}
@Override
public void run()
{
innerLock.lock();
try {
for(int i=1;i<=3;i++){
System.out.println(Thread.currentThread() + " lock " + i);
}
} finally {
innerLock.unlock();
}
}
}
输出结果
说明:不会出现交叉输出的情形,例如 1 1 2 3 2 3 …..,说明线程安全
Thread[pool-1-thread-1,5,main] lock 1
Thread[pool-1-thread-1,5,main] lock 2
Thread[pool-1-thread-1,5,main] lock 3
Thread[pool-1-thread-2,5,main] lock 1
Thread[pool-1-thread-2,5,main] lock 2
Thread[pool-1-thread-2,5,main] lock 3
Thread[pool-1-thread-3,5,main] lock 1
Thread[pool-1-thread-3,5,main] lock 2
Thread[pool-1-thread-3,5,main] lock 3
3、ReentrantLock非公平锁与公平锁
默认是非公平锁:ReentrantLock reenTrantLock = new ReentrantLock(boolean isFair);
非公平锁VS公平锁:1)实际情况下,线程需要连续多次获取锁才能完成逻辑处理;2)非公平锁使得当前线程连续获取锁,而不是按照请求时间先后排队,最终能得到较高的TPS;3)非公平锁容易导致【线程饥饿】,即排队时间长的线程反而获取不到锁
【非公平锁】代码测试
@Override
public void run()
{
for(int i=1;i<=3;i++){
innerLock.lock(); // 在同一个线程内,连续多次获取锁
try {
System.out.println(Thread.currentThread() + " lock " + i);
} finally {
innerLock.unlock();
}
}
}
【非公平锁】测试输出结果
说明:同一个线程内的输出基本是连续的,说明线程内多次尝试获取锁成功概率很高
Thread[pool-1-thread-1,5,main] lock 1
Thread[pool-1-thread-2,5,main] lock 1
Thread[pool-1-thread-2,5,main] lock 2
Thread[pool-1-thread-2,5,main] lock 3
Thread[pool-1-thread-1,5,main] lock 2
Thread[pool-1-thread-1,5,main] lock 3
Thread[pool-1-thread-3,5,main] lock 1
Thread[pool-1-thread-3,5,main] lock 2
Thread[pool-1-thread-3,5,main] lock 3
----end----
【公平锁】代码测试:ReentrantLock reenTrantLock = new ReentrantLock(true);
【公平锁】测试结果:增加线程数后输出结果更明显,排队靠前的线程优先获取锁
Thread[pool-1-thread-1,5,main] lock 1
Thread[pool-1-thread-3,5,main] lock 1
Thread[pool-1-thread-5,5,main] lock 1
Thread[pool-1-thread-2,5,main] lock 2
Thread[pool-1-thread-4,5,main] lock 2
Thread[pool-1-thread-1,5,main] lock 2
Thread[pool-1-thread-3,5,main] lock 2
Thread[pool-1-thread-5,5,main] lock 2
Thread[pool-1-thread-2,5,main] lock 3
Thread[pool-1-thread-4,5,main] lock 3
Thread[pool-1-thread-1,5,main] lock 3
Thread[pool-1-thread-3,5,main] lock 3
Thread[pool-1-thread-5,5,main] lock 3
Thread[pool-1-thread-2,5,main] lock 4
Thread[pool-1-thread-4,5,main] lock 4
Thread[pool-1-thread-1,5,main] lock 4
Thread[pool-1-thread-3,5,main] lock 4
Thread[pool-1-thread-5,5,main] lock 4
Thread[pool-1-thread-2,5,main] lock 5
Thread[pool-1-thread-4,5,main] lock 5
Thread[pool-1-thread-1,5,main] lock 5
Thread[pool-1-thread-3,5,main] lock 5
Thread[pool-1-thread-5,5,main] lock 5
----end----
4、ReentrantReadWriteLock
允许多个线程同时获取读锁
不允许多个线程同时获取写锁
当前有读锁没有被释放,则写锁获取被阻塞
当前有写锁没有被释放或有写锁等待,则读锁获取被阻塞
代码测试
public class ReadWriteLockTest {
public static void main(String[] args){
ReadWriteLock rwLock = new ReentrantReadWriteLock();
final WorkTest workTest = new WorkTest(rwLock);
int threadNum = 3;
for(int i=0;i<threadNum;i++){
new Thread(new Runnable()
{
@Override
public void run()
{
while(true){
workTest.get();
}
}
},"Thread-"+i).start();
}
for(int j=threadNum;j<threadNum*2;j++){
new Thread(new Runnable()
{
@Override
public void run()
{
while(true){
workTest.set();
}
}
},"Thread-"+j).start();
}
}
}
class WorkTest{
private String sharedStr; // 共享的对象
private ReadWriteLock rwLock;
private Random random = new Random();
public WorkTest(ReadWriteLock rwLock){
this.rwLock = rwLock;
}
public void get(){
rwLock.readLock().lock(); // 获取读锁
System.out.println(Thread.currentThread().getName() + " get readLock");
try {
try
{
Thread.sleep(random.nextInt(1000));
}
catch (InterruptedException e)
{
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " read completed: " + sharedStr);
} finally {
rwLock.readLock().unlock();
}
}
public void set(){
rwLock.writeLock().lock(); // 获取写锁
System.out.println(Thread.currentThread().getName() + " got writeLock ");
try {
try
{
Thread.sleep(random.nextInt(1000));
}
catch (InterruptedException e)
{
e.printStackTrace();
}
sharedStr = Integer.toString(random.nextInt(1000));
System.out.println(Thread.currentThread().getName() + " write completed: " + sharedStr);
} finally {
rwLock.writeLock().unlock();
}
}
}
输出结果
Thread-1 get readLock // 两个线程同时持有读锁
Thread-0 get readLock // 两个线程同时持有读锁
Thread-1 read completed: null
Thread-0 read completed: null
Thread-3 got writeLock
Thread-3 write completed: 895
Thread-5 got writeLock
Thread-5 write completed: 64
Thread-4 got writeLock
Thread-4 write completed: 870
Thread-4 got writeLock
Thread-4 write completed: 900
Thread-2 get readLock
Thread-1 get readLock
Thread-0 get readLock
Thread-1 read completed: 900
Thread-0 read completed: 900