高并发--卷4--ReentrantLock扩展的API

前面介绍了基本的Condition.await(),Condition.signal(),Condition.signalAll(),Lock.lock(),Lock.unlock()等方法的使用,这里再介绍一些新的API。在线程池的设计中会起到一些作用。

ReentrantLock.getHoldCount()获取当前Lock下lock()次数

该方法能获取到当前Lock调用了lock()的次数,你可以理解为给一个对象上了几把锁。只有当所有的锁都被释放之后,才能被另外一个线程调用。

import java.util.concurrent.locks.ReentrantLock;

public class T{
    public static void main(String[] args) throws InterruptedException {
        final Server server = new Server();
        Runnable t = new Runnable(){
            @Override
            public void run() {
                server.go();
            }
        };

        Thread t1 = new Thread(t);
        Thread t2 = new Thread(t);
        t1.start();
        t2.start();
    }
}


class Server{
    private ReentrantLock lock = new ReentrantLock(true);
    public void go(){
        try{
            lock.lock();
            lock.lock();
            System.out.println(lock.getHoldCount());
        }finally{
            lock.unlock();
            lock.unlock();
        }
    }
}

输出结果:
2
2

  • 细心的读者会发现,lock()被调用了几次,unlock()就应该被调用几次。
  • ReentrantLock.getQueueLength()获取到争抢当前Lock的线程数量

    该方法能获取到所有线程在调用了Lock.lock()之后调用的await()数量,这就意味着,该方法返回的是有多少个线程进入了waitting状态而等待被唤醒。

    import java.util.concurrent.locks.ReentrantLock;
    
    public class T{
        public static void main(String[] args) throws InterruptedException {
            final Server server = new Server();
            Runnable t = new Runnable(){
                @Override
                public void run() {
                    server.go();
                }
            };
            Thread t1 = new Thread(t);
            Thread t2 = new Thread(t);
            Thread t3 = new Thread(t);
            t1.start();
            t2.start();
            t3.start();
            Thread.sleep(500);
            server.printWaitLength();
        }
    }
    
    
    class Server{
        private ReentrantLock lock = new ReentrantLock(true);
        public void go(){
            try{
                lock.lock();
                Thread.sleep(500000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }finally{
                lock.unlock();
            }
        }
        public void printWaitLength(){
            System.out.println(this.lock.getQueueLength());
        }
    }
    
    

    输出结果:
    2

  • 可以看出,一个线程率先抢到锁,它并没有释放锁,而是进了sleep()状态,我们知道一个线程进人sleep状态并不会释放锁,所以另外两个线程start()之后,需要等待lock的释放,lock被占用,直到sleep状态的线程释放锁,所以这里有两个线程正在等待锁的释放,所以打印2。
  • getWaitQueueLength(Condition)获取当前Lock下进入await()状态的线程数量

    当一个线程调用了condition.await()之后,当前Lock对应Condition的waitQueueLength就会加1,当调用getWaitQueueLength(Condition)之后就会返回对应的waitQueueLength的值,值得注意的是,在调用这个方法时候,需要先调用lock()方法才能调用该方法,否则会报一个.IllegalMonitorStateException的异常。

    import java.util.concurrent.locks.Condition;
    import java.util.concurrent.locks.ReentrantLock;
    
    public class T{
        public static void main(String[] args) throws InterruptedException {
            final Server server = new Server();
            Runnable t = new Runnable(){
                @Override
                public void run() {
                    server.go();
                }
            };
            Thread t1 = new Thread(t);
            Thread t2 = new Thread(t);
            Thread t3 = new Thread(t);
            t1.start();
            t2.start();
            t3.start();
            Thread.sleep(500);
            server.printWaitLength();
        }
    }
    
    
    class Server{
        private ReentrantLock lock = new ReentrantLock();
        private Condition condition = lock.newCondition();
        public void go(){
            try{
                lock.lock();
                condition.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }finally{
                lock.unlock();
            }
        }
        public void printWaitLength(){
            try{
                lock.lock();
                System.out.println(this.lock.getWaitQueueLength(condition));
            }finally{
                lock.unlock();
            }
    
        }
    }

    输出结果:
    3

  • 有的读者可能会问,为什么不直接使用condition.getWaitQueueLength();而这里使用的是lock.getWaitQueueLength(Condition);其实这一点笔者也没有想明白,希望有弄懂了的读者在下方留言。
  • ReentrantLock.hasQueuedThread(Condition)

    判断当前线程是否正在等待lock释放。

    import java.util.concurrent.locks.ReentrantLock;
    
    public class T{
        public static void main(String[] args) throws InterruptedException {
            final Server server = new Server();
            Runnable t = new Runnable(){
                @Override
                public void run() {
                    server.go();
                }
            };
            Thread t1 = new Thread(t);
            Thread t2 = new Thread(t);
            Thread t3 = new Thread(t);
            t1.start();
            t2.start();
            t3.start();
            Thread.sleep(500);
            System.out.println(server.lock.hasQueuedThread(t1));
            System.out.println(server.lock.hasQueuedThread(t2));
            System.out.println(server.lock.hasQueuedThread(t3));
        }
    }
    
    
    class Server{
        public ReentrantLock lock = new ReentrantLock();
        public void go(){
            try{
                lock.lock();
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }finally{
                lock.unlock();
            }
        }
    }

    输出结果:
    false
    true
    true

  • t1线程已经拿到锁,所以打印false
  • t2线程没有拿到锁,正在等待挣抢锁,打印true
  • t3线程没有拿到锁,正在等待争抢锁,打印true
  • ReentrantLock.hasQueuedThreads()

    判断释放有线程正常争抢当前锁。

    import java.util.concurrent.locks.ReentrantLock;
    
    
    public class T{
        public static void main(String[] args) throws InterruptedException {
            final Server server = new Server();
            Runnable runnable = new Runnable() {
                @Override
                public void run() {
                    try {
                        server.go();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            };
            new Thread(runnable).start();
            new Thread(runnable).start();
            new Thread(runnable).start();
            Thread.sleep(500);
            System.out.println(server.lock.hasQueuedThreads());
        }
    }
    
    class Server{
        public ReentrantLock lock = new ReentrantLock();
        public void go() throws InterruptedException{
            try{
                lock.lock();
                Thread.sleep(5000);
            }finally{
                lock.unlock();
            }
        }
    }

    输出结果:
    true

  • 很明显,一个线程率先获取到锁,并sleep(),我们知道sleep()的特性是不放释放锁,所以该线程会占用锁一段事件,其他线程等待该锁的释放。所以这里打印true。
  • ReentrantLock.hasWriters(Condition);

    判断是否有线程通过该Condition处于waitting状态。

    import java.util.concurrent.locks.Condition;
    import java.util.concurrent.locks.ReentrantLock;
    
    
    public class T{
        public static void main(String[] args) throws InterruptedException {
            final Server server = new Server();
            Runnable runnable = new Runnable() {
                @Override
                public void run() {
                    try {
                        server.go();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            };
            new Thread(runnable).start();
            new Thread(runnable).start();
            new Thread(runnable).start();
            Thread.sleep(500);
            server.print();
        }
    }
    
    class Server{
        public ReentrantLock lock = new ReentrantLock();
        private Condition condition = lock.newCondition();
        public void go() throws InterruptedException{
            try{
                lock.lock();
                condition.await();
            }finally{
                lock.unlock();
            }
        }
    
        public void print(){
            try{
                lock.lock();
                System.out.println(lock.hasWaiters(condition));
            }finally{
                lock.unlock();
            }
        }
    }

    输出结果:
    true

    isFiar()

    判断是不是公平锁。在前面的一讲中介绍了什么是公平锁,什么是非公平锁,这里就不再赘述。

    import java.util.concurrent.locks.ReentrantLock;
    
    
    public class T{
        public static void main(String[] args) throws InterruptedException {
            final Server server = new Server();
            System.out.println(server.lock.isFair());
            System.out.println(server.lock2.isFair());
        }
    }
    
    class Server{
        public ReentrantLock lock = new ReentrantLock();
        public ReentrantLock lock2 = new ReentrantLock(true);
    }

    输出结果:
    false
    true

    ReentrantLock.isHoldByCurrentThread()

    用来测试该线程是否已经被上锁。

    import java.util.concurrent.locks.ReentrantLock;
    
    
    public class T{
        public static void main(String[] args) throws InterruptedException {
            final Server server = new Server();
            Runnable runnable = new Runnable(){
                @Override
                public void run() {
                    server.go();
                }
            };
            Thread t1 = new Thread(runnable);
            t1.start();
        }
    }
    
    class Server{
        public ReentrantLock lock = new ReentrantLock();
        public void go(){
            try{
                System.out.println(lock.isHeldByCurrentThread());
                lock.lock();
                System.out.println(lock.isHeldByCurrentThread());
            }finally{
                lock.unlock();
            }
        }
    }

    输出结果:
    false
    true

    isLocked()

    与上面的isHoldByCurrentThread()不同的是,它不是判断当前线程是否加锁,而是用来判断该锁有没有被任意线程持有。

    import java.util.concurrent.locks.ReentrantLock;
    
    
    public class T{
        public static void main(String[] args) throws InterruptedException {
            final Server server = new Server();
            Runnable runnable = new Runnable(){
                @Override
                public void run() {
                    try {
                        server.go();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            };
            Thread t1 = new Thread(runnable);
            t1.start();
            Thread.sleep(500);
            System.out.println(server.lock.isLocked());
        }
    }
    
    class Server{
        public ReentrantLock lock = new ReentrantLock();
        public void go() throws InterruptedException{
            try{
                lock.lock();
                Thread.sleep(5000);
            }finally{
                lock.unlock();
            }
        }
    }

    输出结果:
    true

    lock.tryLock()

    于lock.lock()不同的是,tryLock()只是尝试获取一次锁,没有获取到就不再次获取该锁了。值得注意的是tryLock()也需要通过lock.unlock()释放锁。

    import java.util.concurrent.locks.ReentrantLock;
    
    
    public class T{
        public static void main(String[] args) throws InterruptedException {
            final Server server = new Server();
            Runnable runnable = new Runnable(){
                @Override
                public void run() {
                    try {
                        server.go();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            };
            Thread t1 = new Thread(runnable);
            Thread t2 = new Thread(runnable);
            t1.start();
            t2.start();
            Thread.sleep(500);
            System.out.println(server.lock.hasQueuedThreads());
            Thread.sleep(10000);
            System.out.println(server.lock.isLocked());
        }
    }
    
    class Server{
        public ReentrantLock lock = new ReentrantLock();
        public void go() throws InterruptedException{
            lock.tryLock();
            Thread.sleep(5000);
        }
    }

    输出结果:
    false
    true
    hasQueuedThreads()为false的原因是其中有一个线程获取到了锁并处于sleep状态,另外的线程无法通过tryLock()获取到锁。
    isLocked()打印为true的原因是,tryLock()依然需要通过lock.unlock()释放锁。
    释放锁的列子:修改Server类:

    class Server{
        public ReentrantLock lock = new ReentrantLock();
        public void go() throws InterruptedException{
            try{
                lock.tryLock();
                Thread.sleep(5000);
            }finally{
                if(lock.isHeldByCurrentThread()){   //当前线程是否已经获取了该锁,获取了才能释放
                    lock.unlock();
                }
            }
        }
    }
    

    修改后的输出结果:
    false
    false

  • 值得注意的是:isHeldByCurrentThread()用来判断当前线程释放持有该锁是必要的,当没有这个判断是时候,tryLock()失败的锁也会调用lock.unlock()从而导致异常。
  • ReentrantLock.tryLock(long,TimeUnit)

    该方法将tryLock进行了时间设定,第一个参数为设计的时间长度,第二个参数是时间的单位,在该段时间内会等待lock的释放,并进行tryLock()如果这段时间后还未获取到该岁,那么tryLock()返回false,简单的说,tryLock(long,TimeUnit)其实就是在tryLock()的基础上加了一个计时器。

    import java.util.concurrent.TimeUnit;
    import java.util.concurrent.locks.ReentrantLock;
    
    
    public class T{
        public static void main(String[] args) throws InterruptedException {
            final Server server = new Server();
            Runnable runnable = new Runnable(){
                @Override
                public void run() {
                    try {
                        server.go();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            };
            Thread t1 = new Thread(runnable);
            Thread t2 = new Thread(runnable);
            t1.start();
            Thread.sleep(50);
            t2.start();
            Thread.sleep(500);
            System.out.println(server.lock.hasQueuedThread(t2));
        }
    }
    
    class Server{
        public ReentrantLock lock = new ReentrantLock();
        public void go() throws InterruptedException{
            try{
                lock.tryLock(6000,TimeUnit.MILLISECONDS);
                Thread.sleep(5000);
            }finally{
                if(lock.isHeldByCurrentThread()){   //当前线程是否已经获取了该锁,获取了才能释放
                    lock.unlock();
                }
            }
        }
    }
    

    输出结果:
    true

    猜你喜欢

    转载自blog.csdn.net/qq_25956141/article/details/81124751