ReentrantLock重入锁

来源:互联网 发布:狩猎波尔卡 知乎 编辑:程序博客网 时间:2024/05/01 16:33

1使用案例

public class ReenterLock implements Runnable{    public static ReentrantLock lock=new ReentrantLock();    public static int i=0;    @Override    public void run() {        for (int j = 0; j <100; j++) {            lock.lock();        try{            i++;            System.out.println(Thread.currentThread().getName()+" "+i);        }finally {            lock.unlock();        }        }    }    public static void main(String[] args)throws InterruptedException{        ReenterLock r1=new ReenterLock();        Thread t1=new Thread(r1);        Thread t2=new Thread(r1);        t1.start();        t2.start();        t1.join();        t2.join();        System.out.println(i);    }}
Thread-0 1Thread-0 2Thread-0 3Thread-0 4Thread-0 5Thread-0 6Thread-0 7Thread-0 8Thread-0 9Thread-0 10Thread-0 11Thread-0 12Thread-0 13Thread-0 14Thread-0 15Thread-0 16Thread-0 17Thread-0 18Thread-0 19Thread-0 20Thread-0 21Thread-0 22Thread-0 23Thread-0 24Thread-0 25Thread-0 26Thread-0 27Thread-0 28Thread-0 29Thread-0 30Thread-0 31Thread-0 32Thread-0 33Thread-0 34Thread-0 35Thread-0 36Thread-0 37Thread-0 38Thread-0 39Thread-0 40Thread-0 41Thread-0 42Thread-0 43Thread-0 44Thread-0 45Thread-0 46Thread-0 47Thread-0 48Thread-0 49Thread-0 50Thread-0 51Thread-0 52Thread-0 53Thread-0 54Thread-0 55Thread-0 56Thread-0 57Thread-0 58Thread-0 59Thread-0 60Thread-0 61Thread-0 62Thread-0 63Thread-0 64Thread-0 65Thread-0 66Thread-0 67Thread-0 68Thread-0 69Thread-0 70Thread-0 71Thread-0 72Thread-0 73Thread-0 74Thread-0 75Thread-0 76Thread-0 77Thread-0 78Thread-0 79Thread-0 80Thread-0 81Thread-0 82Thread-0 83Thread-0 84Thread-0 85Thread-0 86Thread-0 87Thread-0 88Thread-0 89Thread-0 90Thread-0 91Thread-0 92Thread-0 93Thread-0 94Thread-0 95Thread-0 96Thread-0 97Thread-0 98Thread-0 99Thread-0 100Thread-1 101Thread-1 102Thread-1 103Thread-1 104Thread-1 105Thread-1 106Thread-1 107Thread-1 108Thread-1 109Thread-1 110Thread-1 111Thread-1 112Thread-1 113Thread-1 114Thread-1 115Thread-1 116Thread-1 117Thread-1 118Thread-1 119Thread-1 120Thread-1 121Thread-1 122Thread-1 123Thread-1 124Thread-1 125Thread-1 126Thread-1 127Thread-1 128Thread-1 129Thread-1 130Thread-1 131Thread-1 132Thread-1 133Thread-1 134Thread-1 135Thread-1 136Thread-1 137Thread-1 138Thread-1 139Thread-1 140Thread-1 141Thread-1 142Thread-1 143Thread-1 144Thread-1 145Thread-1 146Thread-1 147Thread-1 148Thread-1 149Thread-1 150Thread-1 151Thread-1 152Thread-1 153Thread-1 154Thread-1 155Thread-1 156Thread-1 157Thread-1 158Thread-1 159Thread-1 160Thread-1 161Thread-1 162Thread-1 163Thread-1 164Thread-1 165Thread-1 166Thread-1 167Thread-1 168Thread-1 169Thread-1 170Thread-1 171Thread-1 172Thread-1 173Thread-1 174Thread-1 175Thread-1 176Thread-1 177Thread-1 178Thread-1 179Thread-1 180Thread-1 181Thread-1 182Thread-1 183Thread-1 184Thread-1 185Thread-1 186Thread-1 187Thread-1 188Thread-1 189Thread-1 190Thread-1 191Thread-1 192Thread-1 193Thread-1 194Thread-1 195Thread-1 196Thread-1 197Thread-1 198Thread-1 199Thread-1 200200

// lock.unlock();
屏蔽 lock.unlock()这行代码的打印结果,加锁后必须释放锁,否则其他线程无法获取资源

Thread-0 1Thread-0 2Thread-0 3Thread-0 4Thread-0 5Thread-0 6Thread-0 7Thread-0 8Thread-0 9Thread-0 10Thread-0 11Thread-0 12Thread-0 13Thread-0 14Thread-0 15Thread-0 16Thread-0 17Thread-0 18Thread-0 19Thread-0 20Thread-0 21Thread-0 22Thread-0 23Thread-0 24Thread-0 25Thread-0 26Thread-0 27Thread-0 28Thread-0 29Thread-0 30Thread-0 31Thread-0 32Thread-0 33Thread-0 34Thread-0 35Thread-0 36Thread-0 37Thread-0 38Thread-0 39Thread-0 40Thread-0 41Thread-0 42Thread-0 43Thread-0 44Thread-0 45Thread-0 46Thread-0 47Thread-0 48Thread-0 49Thread-0 50Thread-0 51Thread-0 52Thread-0 53Thread-0 54Thread-0 55Thread-0 56Thread-0 57Thread-0 58Thread-0 59Thread-0 60Thread-0 61Thread-0 62Thread-0 63Thread-0 64Thread-0 65Thread-0 66Thread-0 67Thread-0 68Thread-0 69Thread-0 70Thread-0 71Thread-0 72Thread-0 73Thread-0 74Thread-0 75Thread-0 76Thread-0 77Thread-0 78Thread-0 79Thread-0 80Thread-0 81Thread-0 82Thread-0 83Thread-0 84Thread-0 85Thread-0 86Thread-0 87Thread-0 88Thread-0 89Thread-0 90Thread-0 91Thread-0 92Thread-0 93Thread-0 94Thread-0 95Thread-0 96Thread-0 97Thread-0 98Thread-0 99Thread-0 100

有显示的操作过程,必须显示指定何时加锁,何时释放锁。加锁后必须释放锁。
2重入含义
ReentrantLock是可以反复进入的,反复仅仅限于一个线程。一个线程连续两次获得同一把锁是允许的,如果不允许这种操作,线程在第二次申请锁的时候会和自己发生死锁。一个线程加多少次锁,必须释放多少次锁,如果释放的次数少,相当于线程还持有这个锁,其他线程无法
获取资源。

            lock.lock();            lock.lock();        try{            i++;            System.out.println(Thread.currentThread().getName()+" "+i);        }finally {            lock.unlock();            lock.unlock();

3可中断的锁
对于synchronized来说,一个线程在等待锁,结果要么是获得锁,要么就是保持等待的状态。使用重入锁,线程在等待的过程中,程序可以根据需要取消对锁的请求。这对于处理死锁有一定帮助。

public class IntLock implements Runnable{    @Override    public void run() {        try{            if(lock==1) {            //获取锁操作                lock1.lockInterruptibly();                try {                    Thread.sleep(500);                } catch (InterruptedException e) {                }                lock2.lockInterruptibly();            }else{                lock2.lockInterruptibly();                try{                    Thread.sleep(500);                }catch(InterruptedException e){}                lock1.lockInterruptibly();            }        } catch (InterruptedException e) {            e.printStackTrace();        } finally{            if(lock1.isHeldByCurrentThread())                lock1.unlock();            if(lock2.isHeldByCurrentThread())                lock2.unlock();            System.out.println(Thread.currentThread().getId()+":线程退出");        }    }    public static ReentrantLock lock1=new ReentrantLock();    public static ReentrantLock lock2=new ReentrantLock();    int lock;    public IntLock(int lock){        this.lock=lock;    }    public static void main(String[] args)throws InterruptedException{        IntLock r1=new IntLock(1);        IntLock r2=new IntLock(2);        Thread t1=new Thread(r1);        Thread t2=new Thread(r2);        t1.start();        t2.start();        Thread.sleep(1000);        t2.interrupt();    }}

执行结果:
10:线程退出
9:线程退出
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 IntLock.run(IntLock.java:22)
at java.lang.Thread.run(Thread.java:745)

Process finished with exit code 0
线程t1和t2启动后,t1先占用lock1,再占用lock2,t2先占用lock2,再占用lock1,lock.lockInterruptibly()是一个可以对中断进行响应的锁操作,即在锁的等待过程中可以响应中断。两个线程都在等待对方释放锁,两个线程处于死锁状态,执行 t2.interrupt()操作后,t2线程被中断,t2会放弃对lock1的申请,同时释放lock2,线程t1获得lock2锁,继续执行,最后两个线程都退出,t1真正完成工作,t2线程放弃任务直接退出释放资源。
4tryLock()/tryLock(long time,TimeUnit unpublic class TimeLock implements Runnable {
public static ReentrantLock lock=new ReentrantLock();

@Overridepublic void run() {    try{        if(lock.tryLock(5, TimeUnit.SECONDS)){            Thread.sleep(6000);        }else{            System.out.println("get lock failed");        }    }catch (InterruptedException e){        e.printStackTrace();    }finally{        if(lock.isHeldByCurrentThread())lock.unlock();    }}public static void main(String[] args){    TimeLock t1=new TimeLock();    Thread th1=new Thread(t1);    Thread th2=new Thread(t1);    th1.start();    th2.start();}

}
如果超过5秒没有得到锁就会返回false,占用锁的线程持用锁的时间长达6秒,因此另外一个线程无法在5秒的等待时间内获得锁。
锁在大多数情况下,锁的申请都是非公平的,系统会随机地从锁的等待队列中挑选一个。公平的锁会按时间先后顺序,保证先到者先得后到者后得。公平锁的一大特点是:不会产生饥饿。在使用synchronized关键字进行锁控制时,产生的锁是非公平的。
公平锁的创建:
public ReentrantLock(boolean fair)
ReentrantLock lock=new ReentrantLock(true);
实现公平锁必然要维护一个有序队列,因此公平锁的实现成本比较高,性能相对也非常低,默认情况下,锁是非公平的。

public class FairLock implements Runnable {    public static ReentrantLock fairLock = new ReentrantLock(true);    @Override    public void run() {        while (true) {            try {                fairLock.lock();                System.out.println(Thread.currentThread().getName() + "获得锁");            } finally {                fairLock.unlock();            }        }    }    public static void main(String[] args) {        FairLock r1 = new FairLock();        Thread t1 = new Thread(r1, "Thread_t1");        Thread t2 = new Thread(r1, "Thread_t2");        t1.start();        t2.start();    }}
结果:t1 t2交替获得锁Thread_t2获得锁Thread_t1获得锁Thread_t2获得锁Thread_t1获得锁Thread_t2获得锁Thread_t1获得锁Thread_t2获得锁Thread_t1获得锁Thread_t2获得锁

Reentrantlock重要方法整理
lock():获得锁,如果锁被占用,则等待
lockInterruptibly():获得锁,但优先响应中断
tryLock():尝试获得锁,如果成功返回true,失败则返回false。该方法不等待,立即返回。
tryLock(long time,TimeUnit unit):在给定时间内尝试获得锁
unlock():释放锁
重入锁的实现要素:
1原子状态:原子状态使用CAS操作来存储当前锁的状态,判断锁是否已经被别的线程持有。
2等待队列:所有没请求到锁的线程,会进入等待队列等待。待有线程释放锁,系统就能从等待队列中唤醒一个线程,继续工作。
3阻塞原语park()和unpark(),用来挂起和恢复线程。没有得到锁的线程将会被挂起。

原创粉丝点击