1.前言

显式的使用Lock实现类对象加锁是解决共享资源竞争的一个方法,synchronized也可以解决共享资源竞争的问题。原子类AtomicXXX和volatile某些情况也可以解决问题。

synchronized是最常用,如果共享资源被多个任务操作且肯能被某个任务修改,则此资源应为volatile类型。

Lock对象显式的创建、锁定和释放。其主要实现类有ReentrantLock、ReadLock、WriteLock、ReadLockView和WriteLockView,主要方法有void lock(); boolean tryLock(); boolean tryLock(long,TimeUnit) 和 void unlock()等,示意图如下:

lock 住 一个spring管理的对象 lock对象有两个状态分别是_显式

.

2.Lock的基本使用方式

Lock对象可以获得更细粒度的控制

public class AttempLocking  {
    //私有
    private ReentrantLock lock=new ReentrantLock();

    public void untimed(){
        boolean captured=lock.tryLock();//fixme 尝试获取锁
        try{
            System.out.println("tryLock(): "+captured);
        }finally {
            if(captured)//fixme 如果获取锁,这在finally中释放
                lock.unlock();
        }
    }

    public void timed(){
        boolean captured=false;
        try{
            captured=lock.tryLock(2, TimeUnit.SECONDS);//指定等待锁的时间
        }catch (InterruptedException e){
            throw new RuntimeException(e);
        }

        try{
            System.out.println("tryLock(2,TimeUnit.SECONDS): "+captured);
        }finally {
            if(captured)
                lock.unlock();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        final AttempLocking al=new AttempLocking();
        //fixme 相同对象执行两个方法,他们共享lock对象的
        al.untimed();
        al.timed();

        //开始一个获取锁的进程
        new Thread(){
            {setDaemon(true);}//设置为守护进程,即主进程结束,守护进程也结束

            @Override
            public void run() {
                //一般情况下获取锁以后都要在finally中unlock();
                al.lock.lock();
                System.out.println("acquired");
            }
        }.start();
        
        TimeUnit.SECONDS.sleep(1);//当前线程停止一会儿,等待上句代码启动的线程获取到al的锁
        al.untimed();
        al.timed();
    }
}
3.Lock+Condition的使用方式

java1.6之后,内置锁synchronized和Lock性能相近,但是Lock可以实现无条件的、可轮询的、定时的和可中断的锁获取操作,所有加锁的方式都是显式的。

其中Condition对象可以实现线程的挂起和唤醒,他与内置锁的对应关系如下:

  • Object中的wait()方法相当于Condition类中的await()方法,wait(long,timeout)相当于await(long,timeunit)方法;
  • Object中的notify()、notifyAll()相当于Condition类中的signalAll()方法;

使用Condition可以仅仅通知部分使用同一个监视器对象的挂起的线程,示例如下:

public class ConditionDemo {
    private Lock lock=new ReentrantLock();//对象私有
    public Condition conA=lock.newCondition();
    public Condition conB=lock.newCondition();

    public void awaitA(){
        try{
            lock.lock();//加锁
            conA.await();//fixme 用lock对应的Condition对象conA挂起,则用conA才能够唤醒此处挂起的线程
        }catch (InterruptedException e){
            e.printStackTrace();
        }finally {
            lock.unlock();//fixme 一定要记住释放锁;
        }
    }

    public void awaitB(){
        try{
            lock.lock();
            conB.await();
        }catch (InterruptedException e){
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }

    public void signalAll_A(){
        try{
            lock.lock();
            conA.signalAll();// fixme 唤醒所有用lock加锁且用conA挂起的任务
        }finally {
            lock.unlock();
        }
    }
}
4.lock()、tryLock()和tryInterruptibly()的区别
  • void lock():调用后一直阻塞知道获取锁,对应无限制锁
  • boolean tryLock():尝试获取锁,不能则返回FALSE,对应定时锁,通过while可作为轮询锁
  • void lockInterruptibly():同lock(),但是接受中断信号,对应可中断锁