(1)synchronized是独占锁,加锁和解锁的过程自动进行,易于操作,但不够灵活。ReentrantLock也是独占锁,加锁和解锁的过程需要手动进行,不易操作,但非常灵活。
(2)synchronized可重入,因为加锁和解锁自动进行,不必担心最后是否释放锁;ReentrantLock也可重入,但加锁和解锁需要手动进行,且次数需一样,否则其他线程无法获得锁。
(3)synchronized不可响应中断,一个线程获取不到锁就一直等着;ReentrantLock可以相应中断。
ReentrantLock公平锁,等待时间最长的线程先运行
首先做一个简易的售票功能
如下使用了reentrantlock公平锁,结果为
public class T1 {
static int num = 23;
static ReentrantLock lock = new ReentrantLock(true);
public static void main(String[] args) {
new Thread(T1::tt, "文化路").start();
new Thread(T1::tt, "瑞达路").start();
new Thread(T1::tt, "红旗路").start();
}
static void tt() {
String na = Thread.currentThread().getName();
while (num > 1) {
lock.lock();
num--;
System.out.printf("%s:%d%n", na, num);
if (num < 1) {
break;
}
lock.unlock();
}
}
}
reentrantlock可以打断线程
例如一个线程睡眠时间太长,导致其他线程阻塞,则可以打断前一个进程。
public class T4 {
static ReentrantLock lock = new ReentrantLock();
public static void main(String[] args) {
Thread a = new Thread(T4::add, "T1");
a.start();
a.interrupt();
new Thread(() -> {
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
lock.lockInterruptibly();
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程二");
lock.unlock();
}).start();
}
static void add() {
try {
lock.lock();
TimeUnit.SECONDS.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("11");
lock.unlock();
}
}
lockInterruptibly()获取锁,除非当前线程被中断。如果锁没有被其他线程持有,则获取锁并立即返回,将锁持有计数设置为1。如果当前线程已经持有这个锁,那么持有计数加1,该方法立即返回。如果锁被另一个线程持有,那么当前线程会因为线程调度的目的而被禁用,并处于休眠状态,直到发生以下两种情况之一:锁被当前线程获取;或其他线程中断当前线程。如果当前线程获得了锁,那么锁保持计数被设置为1如果当前线程:在进入此方法时设置其中断状态;或在获取锁时被中断然后,InterruptedException被抛出,当前线程的interruptec状态被清除。在此实现中,由于此方法是显式的中断点,因此优先于响应中断,而不是正常或可重入获取锁。
版权声明:本文为weixin_57176230原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。