1.定义
重入锁ReentrantLock,支持重入的锁,表示一个线程对资源的重复加锁。
2.底层实现
每个锁关联一个线程持有者和计数器,当计数器为0时表示该锁没有被任何线程持有,那么任何线程都可能获得该锁而调用相应的方法;成功后,JVM会记下锁的持有线程,并且将计数器置为1;此时其它线程请求该锁,则必须等待;而该持有锁的线程如果再次请求这个锁,就可以再次拿到这个锁,同时计数器会递增;当线程退出同步代码块时,计数器会递减,如果计数器为0,则释放该锁。
3.使用样例
eg:
import java.util.concurrent.locks.ReentrantLock;
public class ReentrantLockTest implements Runnable{
public static int i = 100;
public static ReentrantLock rl = new ReentrantLock();
@Override
public void run() {
while(true){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
rl.lock();
if(i>0){
System.out.println(Thread.currentThread().getName() + " : " + i--);
}
rl.unlock();
}
}
public static void main(String[] args) {
ReentrantLockTest rlt = new ReentrantLockTest();
Thread t1 = new Thread(rlt);
Thread t2 = new Thread(rlt);
t1.start();
t2.start();
}
}
中断响应
synchronized:线程等待锁,要么获得锁继续执行,要么保持等待。
ReentrantLock:等待锁的过程中,可以根据需求取消对锁的请求。
eg:
import java.util.concurrent.locks.ReentrantLock;
public class IntLock implements Runnable {
int lock;
public static ReentrantLock lock1 = new ReentrantLock();
public static ReentrantLock lock2 = new ReentrantLock();
public IntLock(int lock){
this.lock = lock;
}
@Override
public void run() {
try{
if(lock == 1){
try{
lock1.lockInterruptibly(); // 如果当前线程未被中断,则获取锁。
}catch(Exception e){
e.printStackTrace();
}
lock2.lockInterruptibly();
System.out.println(Thread.currentThread().getId()+"执行完毕");
}else{
lock2.lockInterruptibly();
try{
Thread.sleep(1000);
}catch(Exception e){
}
lock1.lockInterruptibly();
}
}catch(Exception e){
e.printStackTrace();
}finally{
if(lock1.isHeldByCurrentThread()){ //查询当前线程是否保持此锁
lock1.unlock();
}
if(lock2.isHeldByCurrentThread()){ //查询当前线程是否保持此锁
lock2.unlock();
}
System.out.println(Thread.currentThread().getId()+":线程退出");
}
}
public static void main(String[] args) throws InterruptedException {
IntLock l1 = new IntLock(1);
IntLock l2 = new IntLock(2);
Thread t1 = new Thread(l1);
Thread t2 = new Thread(l2);
t1.start();
t2.start();
Thread.sleep(2000);
t2.interrupt(); //中断线程,不中断,则产生死锁
}
}
锁申请等待限时
如果锁在给定等待时间内没有被另一个线程保持,且当前线程未被中断,则获取该锁。
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
public class TimeLock implements Runnable {
public static ReentrantLock rl = new ReentrantLock();
@Override
public void run() {
try {
if(rl.tryLock(5, TimeUnit.SECONDS)){
Thread.sleep(6000);
System.out.println(Thread.currentThread().getId()+"执行完毕");
}else{
System.out.println(Thread.currentThread().getId()+"get lock failed");
}
} catch (InterruptedException e) {
e.printStackTrace();
}finally{
if(rl.isHeldByCurrentThread())rl.unlock();
}
}
public static void main(String[] args) {
TimeLock tl = new TimeLock();
Thread t1 = new Thread(tl);
Thread t2 = new Thread(tl);
t1.start();
t2.start();
}
}
公平锁
在ReentrantLock中很明显可以看到其中同步包括两种,分别是公平的FairSync和非公平的NonfairSync。公平锁的作用就是严格按照线程启动的顺序来执行的,不允许其他线程插队执行的;而非公平锁是允许插队的。默认情况下ReentrantLock是通过非公平锁来进行同步的,包括synchronized关键字都是如此,因为这样性能会更好。
public ReentrantLock(boolean fair) //如果此锁应该使用公平的排序策略,则该参数为 true
import java.util.concurrent.locks.ReentrantLock;
public class FairLock implements Runnable{
public static ReentrantLock rl = new ReentrantLock(true);
@Override
public void run() {
while(true){
try {
rl.lock();
System.out.println(Thread.currentThread().getName()+" : get lock");
} catch (Exception e) {
}finally{
rl.unlock();
}
}
}
public static void main(String[] args) {
FairLock fl = new FairLock();
Thread t1 = new Thread(fl,"Thread_One");
Thread t2 = new Thread(fl,"Thread_Two");
t1.start();
t2.start();
}
}
在重入锁的实现中,包含3个要素
1.原子状态,使用CAS操作来存储当前锁的状态,判断锁是否被别的线程持有
2.等待队列,所有没有请求到锁的线程,会进入到队列进行等待,待有线程释放锁后,系统能从等待队列唤醒一个线程继续工作。
3.阻塞原语park()和unpark(),用来挂起和恢复线程,没有得到锁的线程会被挂起
原文地址:https://www.cnblogs.com/Ch1nYK/p/9245153.html
时间: 2024-10-10 18:05:09