前面介绍了基本的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