- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章Java并发之条件阻塞Condition的应用代码示例由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
本文研究的主要是Java并发之条件阻塞Condition的应用示例代码,具体如下.
Condition将Object监视器方法(wait、notify 和 notifyAll)分解成截然不同的对象,以便通过将这些对象与任意Lock实现组合使用,为每个对象提供多个等待 set(wait-set)。其中,Lock 替代了synchronized方法和语句的使用,Condition替代了Object监视器方法的使用.
。
由于Condition可以用来替代wait、notify等方法,所以可以对比着之前写过的线程间通信的代码来看,再来看一下原来那个问题:
有两个线程,子线程先执行10次,然后主线程执行5次,然后再切换到子线程执行10,再主线程执行5次……如此往返执行50次.
之前用wait和notify来实现的,现在用Condition来改写一下,代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
|
public
class
ConditionCommunication {
public
static
void
main(String[] args) {
Business bussiness =
new
Business();
new
Thread(
new
Runnable() {
// 开启一个子线程
@Override
public
void
run() {
for
(
int
i =
1
; i <=
50
; i++) {
bussiness.sub(i);
}
}
}
).start();
// main方法主线程
for
(
int
i =
1
; i <=
50
; i++) {
bussiness.main(i);
}
}
}
class
Business {
Lock lock =
new
ReentrantLock();
Condition condition = lock.newCondition();
//Condition是在具体的lock之上的
private
Boolean bShouldSub =
true
;
public
void
sub(
int
i) {
lock.lock();
try
{
while
(!bShouldSub) {
try
{
condition.await();
//用condition来调用await方法
}
catch
(Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
for
(
int
j =
1
; j <=
10
; j++) {
System.out.println(
"sub thread sequence of "
+ j
+
", loop of "
+ i);
}
bShouldSub =
false
;
condition.signal();
//用condition来发出唤醒信号,唤醒某一个
}
finally
{
lock.unlock();
}
}
public
void
main(
int
i) {
lock.lock();
try
{
while
(bShouldSub) {
try
{
condition.await();
//用condition来调用await方法
}
catch
(Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
for
(
int
j =
1
; j <=
10
; j++) {
System.out.println(
"main thread sequence of "
+ j
+
", loop of "
+ i);
}
bShouldSub =
true
;
condition.signal();
//用condition来发出唤醒信号么,唤醒某一个
}
finally
{
lock.unlock();
}
}
}
|
从代码来看,Condition的使用时和Lock一起的,没有Lock就没法使用Condition,因为Condition是通过Lock来new出来的,这种用法很简单,只要掌握了synchronized和wait、notify的使用,完全可以掌握Lock和Condition的使用.
。
2.1 缓冲区的阻塞队列 。
上面使用Lock和Condition来代替synchronized和Object监视器方法实现了两个线程之间的通信,现在再来写个稍微高级点应用:模拟缓冲区的阻塞队列。 什么叫缓冲区呢?举个例子,现在有很多人要发消息,我是中转站,我要帮别人把消息发出去,那么现在我 就需要做两件事,一件事是接收用户发过来的消息,并按顺序放到缓冲区,另一件事是从缓冲区中按顺序取出用户发过来的消息,并发送出去.
现在把这个实际的问题抽象一下:缓冲区即一个数组,我们可以向数组中写入数据,也可以从数组中把数据取走,我要做的两件事就是开启两个线程,一个存数据,一个取数据。但是问题来了,如果缓冲区满了,说明接收的消息太多了,即发送过来的消息太快了,我另一个线程还来不及发完,导致现在缓冲区没地方放了,那么此时就得阻塞存数据这个线程,让其等待;相反,如果我转发的太快,现在缓冲区所有内容都被我发完了,还没有用户发新的消息来,那么此时就得阻塞取数据这个线程.
好了,分析完了这个缓冲区的阻塞队列,下面就用Condition技术来实现一下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
|
class
Buffer {
final
Lock lock =
new
ReentrantLock();
//定义一个锁
final
Condition notFull = lock.newCondition();
//定义阻塞队列满了的Condition
final
Condition notEmpty = lock.newCondition();
//定义阻塞队列空了的Condition
final
Object[] items =
new
Object[
10
];
//为了下面模拟,设置阻塞队列的大小为10,不要设太大
int
putptr, takeptr, count;
//数组下标,用来标定位置的
//往队列中存数据
public
void
put(Object x)
throws
InterruptedException {
lock.lock();
//上锁
try
{
while
(count == items.length) {
System.out.println(Thread.currentThread().getName() +
" 被阻塞了,暂时无法存数据!"
);
notFull.await();
//如果队列满了,那么阻塞存数据这个线程,等待被唤醒
}
//如果没满,按顺序往数组中存
items[putptr] = x;
if
(++putptr == items.length)
//这是到达数组末端的判断,如果到了,再回到始端
putptr =
0
;
++count;
//消息数量
System.out.println(Thread.currentThread().getName() +
" 存好了值: "
+ x);
notEmpty.signal();
//好了,现在队列中有数据了,唤醒队列空的那个线程,可以取数据啦
}
finally
{
lock.unlock();
//放锁
}
}
//从队列中取数据
public
Object take()
throws
InterruptedException {
lock.lock();
//上锁
try
{
while
(count ==
0
) {
System.out.println(Thread.currentThread().getName() +
" 被阻塞了,暂时无法取数据!"
);
notEmpty.await();
//如果队列是空,那么阻塞取数据这个线程,等待被唤醒
}
//如果没空,按顺序从数组中取
Object x = items[takeptr];
if
(++takeptr == items.length)
//判断是否到达末端,如果到了,再回到始端
takeptr =
0
;
--count;
//消息数量
System.out.println(Thread.currentThread().getName() +
" 取出了值: "
+ x);
notFull.signal();
//好了,现在队列中有位置了,唤醒队列满的那个线程,可以存数据啦
return
x;
}
finally
{
lock.unlock();
//放锁
}
}
}
|
这个程序很经典,我从官方JDK文档中拿出来的,然后加了注释。程序中定义了两个Condition,分别针对两个线程,等待和唤醒分别用不同的Condition来执行,思路很清晰,程序也很健壮。可以考虑一个问题,为啥要用两个Codition呢?之所以这么设计肯定是有原因的,如果用一个Condition,现在假设队列满了,但是有2个线程A和B同时存数据,那么都进入了睡眠,好,现在另一个线程取走一个了,然后唤醒了其中一个线程A,那么A可以存了,存完后,A又唤醒一个线程,如果B被唤醒了,那就出问题了,因为此时队列是满的,B不能存的,B存的话就会覆盖原来还没被取走的值,就因为使用了一个Condition,存和取都用这个Condition来睡眠和唤醒,就乱了套。到这里,就能体会到这个Condition的用武之地了,现在来测试一下上面的阻塞队列的效果:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
|
public
class
BoundedBuffer {
public
static
void
main(String[] args) {
Buffer buffer =
new
Buffer();
for
(
int
i =
0
; i <
5
; i ++) {
//开启5个线程往缓冲区存数据
new
Thread(
new
Runnable() {
@Override
public
void
run() {
try
{
buffer.put(
new
Random().nextint(
1000
));
//随机存数据
}
catch
(InterruptedException e) {
e.printStackTrace();
}
}
}
).start();
}
for
(
int
i =
0
; i <
10
; i ++) {
//开启10个线程从缓冲区中取数据
new
Thread(
new
Runnable() {
@Override
public
void
run() {
try
{
buffer.take();
//从缓冲区取数据
}
catch
(InterruptedException e) {
e.printStackTrace();
}
}
}
).start();
}
}
}
|
我故意只开启5个线程存数据,10个线程取数据,就是想让它出现取数据被阻塞的情况发生,看运行的结果:
Thread-5 被阻塞了,暂时无法取数据! Thread-10 被阻塞了,暂时无法取数据! Thread-1 存好了值: 755 Thread-0 存好了值: 206 Thread-2 存好了值: 741 Thread-3 存好了值: 381 Thread-14 取出了值: 755 Thread-4 存好了值: 783 Thread-6 取出了值: 206 Thread-7 取出了值: 741 Thread-8 取出了值: 381 Thread-9 取出了值: 783 Thread-5 被阻塞了,暂时无法取数据! Thread-11 被阻塞了,暂时无法取数据! Thread-12 被阻塞了,暂时无法取数据! Thread-10 被阻塞了,暂时无法取数据! Thread-13 被阻塞了,暂时无法取数据! 。
从结果中可以看出,线程5和10抢先执行,发现队列中没有,于是就被阻塞了,睡在那了,直到队列中有新的值存入才可以取,但是它们两运气不好,存的数据又被其他线程给抢先取走了,哈哈……可以多运行几次。如果想要看到存数据被阻塞,可以将取数据的线程设置少一点,这里我就不设了.
2.2 两个以上线程之间的唤醒 。
还是原来那个题目,现在让三个线程来执行,看一下题目:
有三个线程,子线程1先执行10次,然后子线程2执行10次,然后主线程执行5次,然后再切换到子线程1执行10次,子线程2执行10次,主线程执行5次……如此往返执行50次.
如过不用Condition,还真不好弄,但是用Condition来做的话,就非常方便了,原理很简单,定义三个Condition,子线程1执行完唤醒子线程2,子线程2执行完唤醒主线程,主线程执行完唤醒子线程1。唤醒机制和上面那个缓冲区道理差不多,下面看看代码吧,很容易理解.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
|
public
class
ThreeConditionCommunication {
public
static
void
main(String[] args) {
Business bussiness =
new
Business();
new
Thread(
new
Runnable() {
// 开启一个子线程
@Override
public
void
run() {
for
(
int
i =
1
; i <=
50
; i++) {
bussiness.sub1(i);
}
}
}
).start();
new
Thread(
new
Runnable() {
// 开启另一个子线程
@Override
public
void
run() {
for
(
int
i =
1
; i <=
50
; i++) {
bussiness.sub2(i);
}
}
}
).start();
// main方法主线程
for
(
int
i =
1
; i <=
50
; i++) {
bussiness.main(i);
}
}
static
class
Business {
Lock lock =
new
ReentrantLock();
Condition condition1 = lock.newCondition();
//Condition是在具体的lock之上的
Condition condition2 = lock.newCondition();
Condition conditionMain = lock.newCondition();
private
int
bShouldSub =
0
;
public
void
sub1(
int
i) {
lock.lock();
try
{
while
(bShouldSub !=
0
) {
try
{
condition1.await();
//用condition来调用await方法
}
catch
(Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
for
(
int
j =
1
; j <=
10
; j++) {
System.out.println(
"sub1 thread sequence of "
+ j
+
", loop of "
+ i);
}
bShouldSub =
1
;
condition2.signal();
//让线程2执行
}
finally
{
lock.unlock();
}
}
public
void
sub2(
int
i) {
lock.lock();
try
{
while
(bShouldSub !=
1
) {
try
{
condition2.await();
//用condition来调用await方法
}
catch
(Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
for
(
int
j =
1
; j <=
10
; j++) {
System.out.println(
"sub2 thread sequence of "
+ j
+
", loop of "
+ i);
}
bShouldSub =
2
;
conditionMain.signal();
//让主线程执行
}
finally
{
lock.unlock();
}
}
public
void
main(
int
i) {
lock.lock();
try
{
while
(bShouldSub !=
2
) {
try
{
conditionMain.await();
//用condition来调用await方法
}
catch
(Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
for
(
int
j =
1
; j <=
5
; j++) {
System.out.println(
"main thread sequence of "
+ j
+
", loop of "
+ i);
}
bShouldSub =
0
;
condition1.signal();
//让线程1执行
}
finally
{
lock.unlock();
}
}
}
}
|
代码看似有点长,但是是假象,逻辑非常简单。关于线程中的Condition技术就总结这么多吧.
。
以上就是本文关于Java并发之条件阻塞Condition的应用代码示例的全部内容,希望对大家有所帮助。感兴趣的朋友可以继续参阅本站其他相关专题,如有不足之处,欢迎留言指出。感谢朋友们对本站的支持! 。
原文链接:http://blog.csdn.net/eson_15/article/details/51559860 。
最后此篇关于Java并发之条件阻塞Condition的应用代码示例的文章就讲到这里了,如果你想了解更多关于Java并发之条件阻塞Condition的应用代码示例的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我正在努力处理查询的 WHERE 部分。查询本身包含一个基于两个表中都存在的 ID 的 LEFT JOIN。但是,我要求 where 语句仅返回其中一列中存在的最大单个结果。目前我返回连接中的所有值,
我有这个代码来改变文件系统的大小。问题是,即使满足 if 条件,它也不会进入 if 条件,而我根本没有检查 if 条件。它直接进入 else 条件。 运行代码后的结果 post-install-ray
假设我有一个包含 2 列的 Excel 表格:单元格 A1 到 A10 中的日期和 B1 到 B10 中的值。 我想对五月日期的所有值求和。我有3种可能性: {=SUM((MONTH(A1:A10)=
伪代码: SELECT * FROM 'table' WHERE ('date' row.date 或 ,我们在Stack Overflow上找到一个类似的问题: https://stackove
我有下面这行代码做一个简单的查询 if ($this->fulfilled) $criteria->addCondition('fulfilled ' . (($this->fulfilled
如果在数据库中找到用户输入的键,我将尝试显示“表”中的数据。目前我已将其设置为让数据库检查 key 是否存在,如下所示: //Select all from table if a key entry
关闭。此题需要details or clarity 。目前不接受答案。 想要改进这个问题吗?通过 editing this post 添加详细信息并澄清问题. 已关闭 5 年前。 Improve th
在MYSQL中可以吗 一共有三个表 任务(task_id、task_status、...) tasks_assigned_to(ta_id、task_id、user_id) task_suggeste
我想先根据用户的状态然后根据用户名来排序我的 sql 请求。该状态由 user_type 列设置: 1=活跃,2=不活跃,3=创始人。 我会使用此请求来执行此操作,但它不起作用,因为我想在“活跃”成员
下面两个函数中最专业的代码风格是什么? 如果函数变得更复杂和更大,例如有 20 个检查怎么办? 注意:每次检查后我都需要做一些事情,所以我不能将所有内容连接到一个 if 语句中,例如: if (veh
我在 C# 项目中使用 EntityFramework 6.1.3 和 SQL Server。我有两个查询,基本上应该执行相同的操作。 1. Exams.GroupBy(x=>x.SubjectID)
我试图在 case when 语句中放入两个条件,但我在 postgresql 中遇到语法错误 case when condition 1 and condition 2 then X else Y
我正在构建一个连接多个表的查询,一个表 prodRecipe 将包含某些行的数据,但不是全部,但是 tmp_inv1 将包含所有行的计数信息。问题是,tmp_inv1.count 取决于某个项目是否在
我有一个涉及 couples of rows which have a less-than-2-hours time-difference 的查询(~0.08333 天): SELECT mt1.*,
我有一个包含许多这样的 OR 条件的代码(工作正常)来检查其中一个值是否为空,然后我们抛出一条错误消息(所有这些都必须填写) } elsif ( !$params{'account'}
我有一个名为 spGetOrders 的存储过程,它接受一些参数:@startdate 和 @enddate。这将查询“订单”表。表中的一列称为“ClosedDate”。如果订单尚未关闭,则此列将保留
在代码中,注释部分是我需要解决的问题...有没有办法在 LINQ 中编写这样的查询?我需要这个,因为我需要根据状态进行排序。 var result = ( from contact in d
我正在尝试创建一个允许省略参数的存储过程,但如果提供了参数,则进行 AND 操作: CREATE PROCEDURE MyProcedure @LastName Varchar(30)
我正在寻找一种方法来过滤我的主机文件中的新 IP 地址。我创建了一个脚本,每次我用来自矩阵企业管理器的数据调用它时都会更新我的主机文件。它工作正常。但是我必须找到一个解决方案,只允许更新 10.XX.
所以我正在做一种 slider ,当它完全向下时隐藏向下按钮,反之亦然,当向上按钮隐藏时,我遇到了问题。 var amount = $('slide').attr('number'); $('span
我是一名优秀的程序员,十分优秀!