1、简介
可重入锁(递归锁),指的是同一线程 外层方法获得锁之后 ,内部方法仍然可以申请获取到该锁。 在 JAVA 环境下 ReentrantLock 和 synchronized 都是 可重入锁。
2、构造器
非公平锁:线程之间相互竞争获取锁,未获取到锁的阻塞等待锁释放。
public ReentrantLock() {
sync = new NonfairSync();
}
示例 1 非公平锁
public static void demo01() throws InterruptedException {
ReentrantLock nonFairLock = new ReentrantLock();
Thread t1 = new Thread(getRunnable(nonFairLock), "t1");
Thread t2 = new Thread(getRunnable(nonFairLock), "t2");
Thread t3 = new Thread(getRunnable(nonFairLock), "t3");
Thread.sleep(3000);
t1.start();
t2.start();
t3.start();
}
private static Runnable getRunnable(ReentrantLock nonFairLock) {
return () -> {
String thName = Thread.currentThread().getName();
System.out.println("线程:" + thName + " 竞争锁");
try {
nonFairLock.lock();
System.out.println("线程:" + thName + " 获取锁,执行任务");
long start = System.currentTimeMillis();
Thread.sleep((long) (Math.random() * 10000));
System.out.println("线程:" + thName + " 完成任务耗时:" + (System.currentTimeMillis() - start));
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
System.out.println("线程:" + thName + " 释放锁=============================");
nonFairLock.unlock();
}
};
}
可重入:同一线程可多次竞争锁
示例 2 可重入
public static void demo02() throws InterruptedException {
ReentrantLock nonFairLock = new ReentrantLock();
Thread t1 = new Thread(getRunnable2(nonFairLock), "t1");
Thread t2 = new Thread(getRunnable2(nonFairLock), "t2");
Thread t3 = new Thread(getRunnable2(nonFairLock), "t3");
Thread.sleep(3000);
t1.start();
t2.start();
t3.start();
}
private static Runnable getRunnable2(ReentrantLock nonFairLock) {
return () -> {
String thName = Thread.currentThread().getName();
System.out.println("线程:" + thName + " 竞争锁");
for (int i = 0; i < 2; i++) {
try {
nonFairLock.lock();
System.out.println("线程:" + thName + " 获取锁,执行任务");
long start = System.currentTimeMillis();
Thread.sleep((long) (Math.random() * 10000));
System.out.println("线程:" + thName + " 完成任务耗时:" + (System.currentTimeMillis() - start));
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
System.out.println("线程:" + thName + " 释放锁=============================");
nonFairLock.unlock();
}
}
};
}
公平锁:锁释放,由等待时间最长的线程获取锁,有顺序。
示例 3 公平锁
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
public static void demo03() throws InterruptedException {
ReentrantLock fairLock = new ReentrantLock(true);
Thread t1 = new Thread(getRunnable3(fairLock), "t1");
Thread t2 = new Thread(getRunnable3(fairLock), "t2");
Thread t3 = new Thread(getRunnable3(fairLock), "t3");
Thread.sleep(3000);
t1.start();
t2.start();
t3.start();
}
private static Runnable getRunnable3(ReentrantLock fairLock) {
return () -> {
String thName = Thread.currentThread().getName();
System.out.println("线程:" + thName + " 竞争锁");
for (int i = 0; i < 2; i++) {
try {
fairLock.lock();
System.out.println("线程:" + thName + " 获取锁,执行任务");
long start = System.currentTimeMillis();
Thread.sleep((long) (Math.random() * 10000));
System.out.println("线程:" + thName + " 完成任务耗时:" + (System.currentTimeMillis() - start));
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
System.out.println("线程:" + thName + " 释放锁=============================");
fairLock.unlock();
}
}
};
}
3、主要方法
lock:获取锁,获取不到就阻塞线程
public void lock() {
sync.lock();
}
unlock:释放锁
public void unlock() {
sync.release(1);
}
tryLock:尝试获取锁,立即返回获取结果,不会阻塞线程
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
设置超时时间参数,该参数时间内获取不到锁就等待,直到超过该参数时间
public boolean tryLock(long timeout, TimeUnit unit)
throws InterruptedException {
return sync.tryAcquireNanos(1, unit.toNanos(timeout));
}
示例 4 tryLock
public static void demo04() throws InterruptedException {
ReentrantLock nonFairLock = new ReentrantLock();
Thread t1 = new Thread(getRunnable4(nonFairLock), "t1");
Thread t2 = new Thread(getRunnable4(nonFairLock), "t2");
Thread t3 = new Thread(getRunnable4(nonFairLock), "t3");
Thread.sleep(3000);
t1.start();
t2.start();
t3.start();
}
private static Runnable getRunnable4(ReentrantLock nonFairLock) {
return () -> {
String thName = Thread.currentThread().getName();
System.out.println("线程:" + thName + " 竞争锁");
try {
while (true) {
if (nonFairLock.tryLock()) {
System.out.println("线程:" + thName + " 获取锁,执行任务");
long start = System.currentTimeMillis();
Thread.sleep((long) (Math.random() * 10000));
System.out.println("线程:" + thName + " 完成任务耗时:" + (System.currentTimeMillis() - start));
break;
} else {
System.out.println("线程:" + thName + " 锁已被持有,先干点别的吧");
Thread.sleep(5000);
}
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
System.out.println("线程:" + thName + " 释放锁=============================");
nonFairLock.unlock();
}
};
}
示例 5 设置超时时间
private static Runnable getRunnable4(ReentrantLock nonFairLock) {
return () -> {
String thName = Thread.currentThread().getName();
System.out.println("线程:" + thName + " 竞争锁");
try {
while (true) {
if (nonFairLock.tryLock(5000, TimeUnit.MILLISECONDS)) {
System.out.println("线程:" + thName + " 获取锁,执行任务");
long start = System.currentTimeMillis();
Thread.sleep((long) (Math.random() * 10000));
System.out.println("线程:" + thName + " 完成任务耗时:" + (System.currentTimeMillis() - start));
break;
} else {
System.out.println("线程:" + thName + " 锁已被持有,先干点别的吧");
}
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
System.out.println("线程:" + thName + " 释放锁=============================");
nonFairLock.unlock();
}
};
}
lockInterruptibly:持有锁线程中断,释放锁,不会继续占有
public void lockInterruptibly() throws InterruptedException {
sync.acquireInterruptibly(1);
}
示例 6 lockInterruptibly
public static void demo05() throws InterruptedException {
ReentrantLock nonFairLock = new ReentrantLock();
Thread t1 = new Thread(getRunnable5(nonFairLock), "t1");
Thread t2 = new Thread(getRunnable5(nonFairLock), "t2");
Thread.sleep(3000);
t1.start();
t2.start();
Thread.sleep(1000);
t2.interrupt();
}
private static Runnable getRunnable5(ReentrantLock nonFairLock) {
return () -> {
String thName = Thread.currentThread().getName();
System.out.println("线程:" + thName + " 竞争锁");
try {
nonFairLock.lockInterruptibly();
System.out.println("线程:" + thName + " 获取锁,执行任务");
long start = System.currentTimeMillis();
Thread.sleep((long) (Math.random() * 10000));
System.out.println("线程:" + thName + " 完成任务耗时:" + (System.currentTimeMillis() - start));
} catch (InterruptedException e) {
System.out.println("线程:" + thName + " 线程中断");
} finally {
System.out.println("线程:" + thName + " 释放锁=============================");
nonFairLock.unlock();
}
};
}
|