Java多线程编程-(6)-你还在使用wait/notify实现进程间的通信吗?
前几篇:
Java多线程编程-(1)-线程安全和锁Synchronized概念
Java多线程编程-(2)-可重入锁以及Synchronized的其他基本特性
Java多线程编程-(3)-从一个错误的双重校验锁代码谈一下volatile关键字
Java多线程编程-(4)-线程本地ThreadLocal的介绍与使用
在《Java多线程编程-(5)-线程间通信机制的介绍与使用》已经学习了,可以使用方法wait/notify
结合同步关键字synchronized实现同步和线程间通信,下边介绍一种更为方便的方式实现同步和线程间通信的效果,那就是Lock对象。
这里为什么说Lock对象哪?Lock其实是一个接口,在JDK1.5以后开始提供,其实现类常用的有ReentrantLock,这里所说的Lock对象即是只Lock接口的实现类,为了方便记忆或理解,都简称为Lock对象。
我们知道synchronized关键字可以实现线程间的同步互斥,从JDK1.5开始新增的ReentrantLock类能够达到同样的效果,并且在此基础上还扩展了很多实用的功能,比使用synchronized更佳的灵活。
下边,就开始一起学习一下ReentrantLock对象。
运行结果:
可以看出,当前线程打印完毕之后释放锁,其他线程才可以获取锁然后进行打印。线程打印的数据是分组打印的,这是因为当前线程已经持有锁,在当前线程打印完之后才会释放锁,但线程之间打印的顺序是随机的。
为了进一步说明使用ReentrantLock可以实现线程之间同步,测试代码如下:
运行结果:
可以看出,在sleep指定的时间内,当调用了lock.lock()方法线程就持有了”对象监视器”,其他线程只能等待锁被释放后再次争抢,效果和使用synchronized关键字是一样的。
上述,已经大致看了一下如何使用ReentrantLock实现线程之间的同步,下边再看一下ReentrantLock是如何实现线程间通信的。
在前文中我们已经知道可以使用关键字synchronized与wait()方法和notify()方式结合实现线程间通信,也就是等待/通知模式。在ReentrantLock中,是借助Condition对象进行实现的。
Condition的创建方式如下:
Condition按字面意思理解就是条件,当然,我们也可以将其认为是条件进行使用,这样的话我们可以通过上述的代码创建多个Condition条件,我们就可以根据不同的条件来控制现成的等待和通知。而我们还知道,在使用关键字synchronized与wait()方法和notify()方式结合实现线程间通信的时候,notify/notifyAll的通知等待的线程时是随机的,显然使用Condition相对灵活很多,可以实现”选择性通知”。
这是因为,synchronized关键字相当于整个Lock对象只有一个单一的Condition对象,所有的线程都注册到这个对象上。线程开始notifAll的时候,需要通知所有等待的线程,让他们开始竞争获得锁对象,没有选择权,这种方式相对于Condition条件的方式在效率上肯定Condition较高一些。
下边,我们首先看一个实例。
主要方法对比如下:
(1)Object的wait()方法相当于Condition类中的await()方法;
(2)Object的notify()方法相当于Condition类中的signal()方法;
(3)Object的notifyAll()方法相当于Condition类中的signalAll()方法;
首先,使用Lock的时候,和《Java多线程编程-(4)-线程间通信机制的介绍与使用》介绍的一样,都需要先获取锁。
示例代码如下:
运行结果:
可以看出结果正确执行!
示例代码如下:
运行结果:
可以看出实现了分别通知。因此,我们可以使用Condition进行分组,可以单独的通知某一个分组,另外还可以使用signalAll()方法实现通知某一个分组的所有等待的线程。
概念很好理解,公平锁表示线程获取锁的顺序是按照线程加锁的顺序来分配,即先进先出,那么他就是公平的;非公平是一种抢占机制,是随机获得锁,并不是先来的一定能先得到锁,结果就是不公平的。
ReentrantLock提供了一个构造方法,可以很简单的实现公平锁或非公平锁,源代码构造函数如下:
参数:fair为true表示是公平锁,反之为非公平锁,这里不再写代码测试。
ReentrantLock源代码结构如下:
方法很简单,看到名称就可以想到作用是什么,挑一些简单介绍一下:
(1)getHoldCount()方法:查询当前线程保持此锁定的个数,也就是调用lock()的次数;
(2)getQueueLength()方法:返回正等待获取此锁定的线程估计数目;
(3)isFair()方法:判断是不是公平锁;
其他的不在介绍。
注:查看源代码请点击阅读原文,PC端效果更佳!