在之前的文章中我们讲到过Java SDK并发包的lock有别于synchronized的隐式锁的三个特性:能够响应中断、支持超时和非阻塞的获取锁。那么今天我们再来详细聊聊Java SDK并发包里的condition。Condition实现了管程模型里面的条件变量。
在之前我们提到过,Java语言内置的管程里只有一个条件变量,而lock &condition实现的管程是支持多个条件变量的,这是二者的一个重要区别。
在很多并发场景下,支持多个条件变量能够让我们的并发程序可读性更好,实现起来也更容易。例如实现一个阻塞队列就需要两个条件变量。
那如何利用两个条件变量快速实现阻塞队列呢?
一个阻塞队列需要两个条件变量,一个是队列不空,空队列不允许出队,另一个是队列不满,队列已满不允许入队。这个例子我们在前面介绍完成的时候详细说过,这里就不再赘述。
不过这里你需要注意lock和condition实现的管程,线程等待和通知需要调用await single singleAll,他们的语义和wait notify notifyAll是相同的,但不一样的是lock & condition实现的管程里,只能使用前面的await single singleAll,而后面的wait notify notifyAll只有在synchronized实现的管程里才能使用。如果一不小心在lock & condition实现的管程里调用了wait notify notifyAll,那程序可就彻底玩完了。
Java SDK并发包里的lock和condition不过是管程的一种实现,管程你已经很熟悉了,那lock 和 condition的使用自然是小菜一碟,下面我们就来看看在知名项目Dubbo中,Lock和condition是怎么使用的?在不过在开始介绍源码之前,我还要先介绍两个概念:同步和异步。
同步与异步
我们平时写的代码基本都是同步的,但最近几年异步编程大火。那同步和异步的区别到底是什么呢?通俗点来讲,就是调用方是否需要等待结果,如果需要等待结果,那就就是同步,如果不需要等待结果就是异步。
比如在下面的代码里,有一个计算圆周率小数点后100万位的方法pai1M(),这个方法可能需要执行俩礼拜,如果调用之后,线程一直等待着计算结果,等俩礼拜之后返回,就可以执行printf(" hello world")了,这个属于同步;如果调用线程不需要等待计算结果,可就立刻可以执行printf(" hello world"),这个就属于异步。
//计算圆周率小数点后100万位
String pai1M(){
//省略代码无数
}
pai1M()
printf("hello woeld")
同步是Java代码默认的处理方式。如果你想让你的线程程序支持异步,可以通过下面两种方式来实现:
调用方创建一个子线程,在子线程里执行方法调用,这种调用我们称为异步调用;
方法实现的时候,创建一个新的线程执行主要逻辑,主线程直接return,这种方法我们一般称为异步方法。
Dubbo源码分析
其实在编程领域,异步的场景还是挺多的,比如TCP协议本身就是异步的,我们工作中经常用到的RPC调用,在TCP协议层面,发送完RPC请求后,线程是不会等待RPC的响应结果的