高并发--卷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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值