美文网首页
【Java并发】显式锁

【Java并发】显式锁

作者: Rockie_h | 来源:发表于2018-03-25 23:55 被阅读18次

    Lock与ReentrantLock

    ReentrantLock实现了Lock接口,并提供了与synchronized相同的互斥性和内存可见性,在获取ReentrantLock时,有着与同步代码块相同的内存语义,在释放ReentrantLock时,有着与退出同步代码块相同的内存语义。此外,与synchronized一样,ReentrantLock提供了可重入的加锁语义。
    两者比较:
    1 显式锁提供定时的锁等待、可中断的锁等待、公平性,以及非块结构的加锁。性能提升;
    2 内置锁更简洁,使用风险更低,显式锁需要显式的调用方法释放锁。
    3 未来性能可能持续提升的是内置锁,因为内置锁是JVM的内置属性,它能执行一些优化。
    4 Lock无法像内置锁那样自动释放,需要显式释放锁,增加了开发应用的风险。

    public interface Lock
    {
        //获取锁
        void lock();
        //如果当前线程未被中断,则获取锁
        void lockInterruptibly() throws 
    InterruptedException;
        //如果锁可用,则获取锁,并立即返回值 true。如果锁不可用,则此方法将立即返回值 false。
        boolean tryLock();
        //如果锁在给定的等待时间内空闲,并且当前线程未被中断,则获取锁
        boolean tryLock(long timeout, TimeUnit unit)
            throws InterruptedException;
        //释放锁
        void unlock();
        //返回绑定到此Lock实例的新Condition实例
        Condition newCondition();  
    }
    

    示例一:使用ReentantLock保护对象状态的典型用法:

    Lock lock = new ReentrantLock();
    ...
    lock.lock();
    try
    {
        //更新对象状态
        //捕获异常,并在必要时恢复不变性条件
    }
    finally
    {
        //必须在finally中显式的释放锁
        lock.unlock();
    }
    

    示例二:通过tryLock来避免顺序死锁:

    private void transfer(Account fromAccount, Account toAccount, int transferAmount, long deadTime)
                {
                    long starttime = System.currentTimeMillis();
                    while(true)
                    {
                        //尝试获取锁,如果失败,则循环尝试,直到获取锁或者超时
                        if(fromAccount.getLock().tryLock()) 
                        {
                            try
                            {
                                if(toAccount.getLock().tryLock())   
                                {
                                    try
                                    {
                                        fromAccount.withDraw(transferAmount);
                                        toAccount.deposit(transferAmount);
                                        count++;
                                        //System.out.println("run count = " + count);
                                    }
                                    finally
                                    {
                                        fromAccount.getLock().unlock();
                                    }
                                }
                            }
                            finally
                            {
                                fromAccount.getLock().unlock();
                            }
                        }
                        try 
                        {
                            Thread.sleep(1000);
                        }
                        catch (InterruptedException e) 
                        {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        };
                        if((System.currentTimeMillis() - starttime) < deadTime)
                        {
                            return;
                        }
                    }
                }
    

    定时锁与轮询锁的锁获取模式是由tryLock实现的。与内置锁相比,使用tryLock如果不能获取需要的锁,可以使用可定时的或可轮询的锁获取方式,从而重新获得控制权,它会释放已经获得的锁,然后重新尝试获取所有锁(或者至少会记录失败日志,或采取其他措施)。
    示例三:可中断的锁获取方式lockInterruptibly:

    //todo
    

    lockInterruptibly方法能够在获得锁的同时保持对中断的响应。
    仅当内置锁不能满足要求时,才应该考虑使用ReentrantLock的一些高级功能,包括:可定时的、可轮询的与可中断的锁获取操作,公平队列,以及非块结构的锁。否则,还是应该优先使用synchronized。

    公平锁

    ReentrantLock构造函数提供了两种公平性选择:非公平锁(默认)或者公平锁。
    公平锁:线程将按照它们发出请求的顺序来获得锁;
    非公平锁:允许“插队”,如果在发出请求的同时,该锁的状态变为可用,那么这个线程将跳过队列中所有的等待线程并获得这个锁。只有当锁被某个线程持有时,新发出请求的线程才会被放入队列;

    大多数情况下,非公平锁的性能高于公平锁:
    1 公平锁由于在挂起线程和恢复线程时的开销而极大的降低性能;
    2 恢复一个挂起的线程与该线程真正开始运行之间存在严重的延迟;
    当持有锁的时间相对较长,或者请求锁的平均时间间隔较长,那么应该使用公平锁。

    读写锁

    ReentrantLock的互斥规则过于强硬。可通过读写锁进行优化。
    一个资源可以被多个读操作访问,或者被一个写操作访问,但两者不能同时进行。
    接口:ReadWriteLock
    实现类:ReentrantReadWriteLock

    public interface ReadWriteLock
    {
        Lock readLock();
        Lock writeLock();
    }
    

    相关文章

      网友评论

          本文标题:【Java并发】显式锁

          本文链接:https://www.haomeiwen.com/subject/uoxlcftx.html