Java编程中实现Condition控制线程通信

2025-05-29 0 14

java中控制线程通信的方法

1.传统的方式:利用synchronized关键字来保证同步,结合wait(),notify(),notifyAll()控制线程通信。不灵活。

2.利用Condition控制线程通信,灵活。

3.利用管道pipe进行线程通信,不推荐

4.利用BlockingQueue控制线程通信

本文就讲解利用Condition控制线程通信,非常灵活的方式。

Condition类是用来保持Lock对象的协调调用。

对Lock不了解的可以参考:Java线程同步Lock同步锁代码示例

Condition介绍

使用Condition可以让那些已经得到lock对象却无法继续执行的线程释放lock对象,Condition对象也可以唤醒处于等待的线程

Condition 将 Object 监视器方法(wait、notify 和 notifyAll)分解成截然不同的对象,以便通过将这些对象与任意 Lock 实现组合使用,为每个对象提供多个等待 set(wait-set)。其中,Lock 替代了 synchronized 方法和语句的使用,Condition 替代了 Object 监视器方法的使用。

Condition 实例实质上被绑定到一个锁上。要为特定 Lock 实例获得 Condition 实例,使用其 newCondition() 方法。

Condition类提供了如下三个方法:

await():造成当前线程在接到信号或被中断之前一直处于等待状态。 该方法流程:

1.新建Condition Node包装线程,加入Condition队列。

2.释放当前线程占有的锁

3.阻塞当前线程

signal():唤醒当前lock对象的一个等待线程。signal方法只是将Node(await方法封装的)修改了状态,并没有唤醒线程。要将修改状态后的Node唤醒,一种是再次调用await(),一种是调用unlock()。//这局句很重要,不明白的可以看我下一篇博客。

signalAll():唤醒当前lock对象的所有等待线程。只有当前线程放弃对lock的锁定,被唤醒的线程才可以执行。

代码实例:

代码逻辑:Account类实现同步的取钱(draw)、存钱(deposit)操作;DrawThread循环取钱的线程、DepositThread循环存钱的线程

Account:

?

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

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127
package condition;

import java.util.concurrent.locks.*;

/**

*存钱、取钱

*/

public class Account

{

//显示定义Lock对象

private final Lock lock = new ReentrantLock();//可重入锁

//获得指定Lock对象对应的条件变量

private final Condition cond = lock.newCondition(); //获得condition实例

private String accountNo;

private double balance;

//标识账户中是否已经存款的旗标

private boolean flag = false;

public Account(){}

public Account(String accountNo , double balance)

{

this.accountNo = accountNo;

this.balance = balance;

}

public void setAccountNo(String accountNo)

{

this.accountNo = accountNo;

}

public String getAccountNo()

{

return this.accountNo;

}

public double getBalance()

{

return this.balance;

}

/**

*取款

* @param drawAmount

*/

public void draw(double drawAmount)

{

//加锁

lock.lock();

System.out.println(Thread.currentThread().getName() +"进入封锁区。。。。。。。。");

try

{

//如果账户中还没有存入存款,该线程等待

if (!flag)

{

cond.await();

}

else

{

//执行取钱操作

System.out.println(Thread.currentThread().getName() +

" 取钱:" + drawAmount);

balance -= drawAmount;

System.out.println("账户余额为:" + balance);

//将标识是否成功存入存款的旗标设为false

flag = false;

//唤醒该Lock对象对应的其他线程

cond.signalAll();

}

}

catch (InterruptedException ex)

{

ex.printStackTrace();

}

//使用finally块来确保释放锁

finally

{

lock.unlock();

System.out.println("释放了");

}

}

/**

* 存款

* @param depositAmount

*/

public void deposit(double depositAmount)

{

lock.lock();

System.out.println(Thread.currentThread().getName() +"进入封锁区。。。。。。。。");

try

{

//如果账户中已经存入了存款,该线程等待

if(flag)

{

System.out.println(Thread.currentThread().getName() +"等待。。。。。。");

cond.await();

}

else

{

//执行存款操作

System.out.println(Thread.currentThread().getName() +

" 存款:" + depositAmount);

balance += depositAmount;

System.out.println("账户余额为:" + balance);

//将标识是否成功存入存款的旗标设为true

flag = true;

//唤醒该Lock对象对应的其他线程

cond.signalAll();

}

}

catch (InterruptedException ex)

{

ex.printStackTrace();

}

//使用finally块来确保释放锁

finally

{

lock.unlock();

System.out.println(Thread.currentThread().getName() +"释放锁。。。。");

}

}

public int hashCode()

{

return accountNo.hashCode();

}

public boolean equals(Object obj)

{

if (obj != null && obj.getClass() == Account.class)

{

Account target = (Account)obj;

return target.getAccountNo().equals(accountNo);

}

return false;

}

}

DrawThread:

?

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
package condition;

/**

*取钱

*/

public class DrawThread extends Thread

{

//模拟用户账户

private Account account;

//当前取钱线程所希望取的钱数

private double drawAmount;

public DrawThread(String name , Account account ,

double drawAmount)

{

super(name);

this.account = account;

this.drawAmount = drawAmount;

}

//当多条线程修改同一个共享数据时,将涉及到数据安全问题。

public void run()

{

for (int i = 0 ; i < 6 ; i++ )

{

account.draw(drawAmount);

}

}

}

DepositThread:

?

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
package condition;

/**

*存钱

*/

public class DepositThread extends Thread

{

//模拟用户账户

private Account account;

//当前取钱线程所希望取的钱数

private double depositAmount;

public DepositThread(String name , Account account ,

double depositAmount)

{

super(name);

this.account = account;

this.depositAmount = depositAmount;

}

//当多条线程修改同一个共享数据时,将涉及到数据安全问题。

public void run()

{

for (int i = 0 ; i < 2 ; i++ )

{

account.deposit(depositAmount);

System.out.println(Thread.currentThread().getName()+" 存钱结束!");

}

}

}

TestDraw:

?

1

2

3

4

5

6

7

8

9

10

11

12

13
package condition;

public class TestDraw

{

public static void main(String[] args)

{

//创建一个账户

Account acct = new Account("1234567" , 0);

new DrawThread("取钱者" , acct , 800).start();

new DepositThread("存钱者甲" , acct , 800).start();

new DepositThread("存钱者乙" , acct , 800).start();

new DepositThread("存钱者丙" , acct , 800).start();

}

}

运行结果:

取钱者进入封锁区。。。。。。。。
存钱者甲进入封锁区。。。。。。。。
存钱者甲 存款:800.0
账户余额为:800.0
存钱者甲释放锁。。。。
存钱者丙进入封锁区。。。。。。。。
存钱者甲 存钱结束!
存钱者丙等待。。。。。。
存钱者乙进入封锁区。。。。。。。。
存钱者乙等待。。。。。。
释放了
存钱者甲进入封锁区。。。。。。。。
存钱者甲等待。。。。。。
取钱者进入封锁区。。。。。。。。
取钱者 取钱:800.0
账户余额为:0.0
释放了
取钱者进入封锁区。。。。。。。。

这里结果只粘贴了一部分。。。。聪明的你会发现这个程序最后阻塞啦,注意是阻塞不是死锁!阻塞的原因是:三个存钱的线程都运行结束了,但是取钱的线程还没有,所以阻塞啦。

总结

以上就是本文关于Java编程中实现Condition控制线程通信的全部内容,希望对大家有所帮助。有什么问题可以随时留言,小编会及时回复大家的。感谢朋友们对本站的支持!

原文链接:http://www.cnblogs.com/jycboy/p/5623210.html

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。

快网idc优惠网 建站教程 Java编程中实现Condition控制线程通信 https://www.kuaiidc.com/114007.html

相关文章

发表评论
暂无评论