0°

Java多线程编程-(6)-你还在使用wait/notify实现进程间的通信吗?

内容预览:
  • 线程打印的数据是分组打印的,这是因为当前线程已经持有锁,在当前线程...~
  • 在前文中我们已经知道可以使用关键字synchronized与wait()方法和notify(...~
  • 下边,我们首先看一个实例~

始发于微信公众号: Java后端技术

前几篇:


在《Java多线程编程-(5)-线程间通信机制的介绍与使用》已经学习了,可以使用方法wait/notify 结合同步关键字synchronized实现同步和线程间通信,下边介绍一种更为方便的方式实现同步和线程间通信的效果,那就是Lock对象。

Lock对象简介

这里为什么说Lock对象哪?Lock其实是一个接口,在JDK1.5以后开始提供,其实现类常用的有ReentrantLock,这里所说的Lock对象即是只Lock接口的实现类,为了方便记忆或理解,都简称为Lock对象。

我们知道synchronized关键字可以实现线程间的同步互斥,从JDK1.5开始新增的ReentrantLock类能够达到同样的效果,并且在此基础上还扩展了很多实用的功能,比使用synchronized更佳的灵活。

下边,就开始一起学习一下ReentrantLock对象。

ReentrantLock实现线程同步

Java多线程编程-(6)-你还在使用wait/notify实现进程间的通信吗?

运行结果:

Java多线程编程-(6)-你还在使用wait/notify实现进程间的通信吗?

可以看出,当前线程打印完毕之后释放锁,其他线程才可以获取锁然后进行打印。线程打印的数据是分组打印的,这是因为当前线程已经持有锁,在当前线程打印完之后才会释放锁,但线程之间打印的顺序是随机的。

为了进一步说明使用ReentrantLock可以实现线程之间同步,测试代码如下:

Java多线程编程-(6)-你还在使用wait/notify实现进程间的通信吗?

运行结果:

Java多线程编程-(6)-你还在使用wait/notify实现进程间的通信吗?

可以看出,在sleep指定的时间内,当调用了lock.lock()方法线程就持有了”对象监视器”,其他线程只能等待锁被释放后再次争抢,效果和使用synchronized关键字是一样的。

使用Lock对象实现线程间通信

上述,已经大致看了一下如何使用ReentrantLock实现线程之间的同步,下边再看一下ReentrantLock是如何实现线程间通信的。

在前文中我们已经知道可以使用关键字synchronized与wait()方法和notify()方式结合实现线程间通信,也就是等待/通知模式。在ReentrantLock中,是借助Condition对象进行实现的。

Condition的创建方式如下:

Java多线程编程-(6)-你还在使用wait/notify实现进程间的通信吗?

Condition按字面意思理解就是条件,当然,我们也可以将其认为是条件进行使用,这样的话我们可以通过上述的代码创建多个Condition条件,我们就可以根据不同的条件来控制现成的等待和通知。而我们还知道,在使用关键字synchronized与wait()方法和notify()方式结合实现线程间通信的时候,notify/notifyAll的通知等待的线程时是随机的,显然使用Condition相对灵活很多,可以实现”选择性通知”。

这是因为,synchronized关键字相当于整个Lock对象只有一个单一的Condition对象,所有的线程都注册到这个对象上。线程开始notifAll的时候,需要通知所有等待的线程,让他们开始竞争获得锁对象,没有选择权,这种方式相对于Condition条件的方式在效率上肯定Condition较高一些。

下边,我们首先看一个实例。

使用Lock对象和Condition实现等待/通知实例

主要方法对比如下:

(1)Object的wait()方法相当于Condition类中的await()方法; 
(2)Object的notify()方法相当于Condition类中的signal()方法; 
(3)Object的notifyAll()方法相当于Condition类中的signalAll()方法;

首先,使用Lock的时候,和《Java多线程编程-(4)-线程间通信机制的介绍与使用》介绍的一样,都需要先获取锁。

示例代码如下:

Java多线程编程-(6)-你还在使用wait/notify实现进程间的通信吗?

运行结果:

Java多线程编程-(6)-你还在使用wait/notify实现进程间的通信吗?

可以看出结果正确执行!

使用Lock对象和多个Condition实现等待/通知实例

示例代码如下:

Java多线程编程-(6)-你还在使用wait/notify实现进程间的通信吗?

运行结果:

Java多线程编程-(6)-你还在使用wait/notify实现进程间的通信吗?

可以看出实现了分别通知。因此,我们可以使用Condition进行分组,可以单独的通知某一个分组,另外还可以使用signalAll()方法实现通知某一个分组的所有等待的线程。

公平锁和非公平锁

概念很好理解,公平锁表示线程获取锁的顺序是按照线程加锁的顺序来分配,即先进先出,那么他就是公平的;非公平是一种抢占机制,是随机获得锁,并不是先来的一定能先得到锁,结果就是不公平的。

ReentrantLock提供了一个构造方法,可以很简单的实现公平锁或非公平锁,源代码构造函数如下:

Java多线程编程-(6)-你还在使用wait/notify实现进程间的通信吗?

参数:fair为true表示是公平锁,反之为非公平锁,这里不再写代码测试。

ReentrantLock的其他方法

ReentrantLock源代码结构如下:

Java多线程编程-(6)-你还在使用wait/notify实现进程间的通信吗?

方法很简单,看到名称就可以想到作用是什么,挑一些简单介绍一下:

(1)getHoldCount()方法:查询当前线程保持此锁定的个数,也就是调用lock()的次数;

(2)getQueueLength()方法:返回正等待获取此锁定的线程估计数目;

(3)isFair()方法:判断是不是公平锁;

其他的不在介绍。

注:查看源代码请点击阅读原文,PC端效果更佳!

和大佬一起学习网络安全知识

以上就是:Java多线程编程-(6)-你还在使用wait/notify实现进程间的通信吗? 的全部内容

本站部分内容来源于互联网和用户投稿,如有侵权请联系我们删除,谢谢^^
Email:[email protected]


0 条回复 A 作者 M 管理员
    所有的伟大,都源于一个勇敢的开始!
欢迎您,新朋友,感谢参与互动!欢迎您 {{author}},您在本站有{{commentsCount}}条评论