博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[转载]Java多线程同步教程--BusyFlag或Locknbsp;(上)
阅读量:2447 次
发布时间:2019-05-10

本文共 3863 字,大约阅读时间需要 12 分钟。

Java多线程同步教程--BusyFlag或Locknbsp;(上)
Java语言内置了synchronized关键字用于对多线程进行同步,大大方便了Java中多线程程序的编写。但是仅仅使用 synchronized关键字还不能满足对多线程进行同步的所有需要。大家知道,synchronized仅仅能够对方法或者代码块进行同步,如果我们 一个应用需要跨越多个方法进行同步,synchroinzed就不能胜任了。在C++中有很多同步机制,比如信号量、互斥体、临届区等。在Java中也可 以在synchronized语言特性的基础上,在更高层次构建这样的同步工具,以方便我们的使用。
当前,广为使用的是由Doug Lea编写的一个Java中同步的工具包,可以在这儿了解更多这个包的详细情况:
该工具包已经作为JSR166正处于JCP的控制下,即将作为JDK1.5的正式组成部分。本文并不打算详细剖析这个工具包,而是对多种同步机制的一个介 绍,同时给出这类同步机制的实例实现,这并不是工业级的实现。但其中会参考Doug Lea的这个同步包中的工业级实现的一些代码片断。
本例中还沿用上篇中的Account类,不过我们这儿编写一个新的ATM类来模拟自动提款机,通过一个ATMTester的类,生成10个ATM线程,同时对John账户进行查询、提款和存款操作。Account类做了一些改动,以便适应本篇的需要:
  1. import java.util.;
  2. import java.util.;
  3. class Account {
  4. name;
  5. //float amount;
  6. //使用一个Map模拟持久存储
  7. static storage = new ();
  8. static {
  9. storage.put("John", new (1000.0f));
  10. storage.put("Mike", new (800.0f));
  11. }
  12. public Account( name) {
  13. //System.out.println("new account:" + name);
  14. this.name = name;
  15. //this.amount = ((Float)storage.get(name)).floatValue();
  16. }
  17. public synchronized void deposit(float amt) {
  18. float amount = (()storage.get(name)).floatValue();
  19. storage.put(name, new (amount + amt));
  20. }
  21. public synchronized void withdraw(float amt) throws InsufficientBalanceException {
  22. float amount = (()storage.get(name)).floatValue();
  23. if (amount >= amt)
  24. amount -= amt;
  25. else
  26. throw new InsufficientBalanceException();
  27. storage.put(name, new (amount));
  28. }
  29. public float getBalance() {
  30. float amount = (()storage.get(name)).floatValue();
  31. return amount;
  32. }
  33. }
在新的Account类中,我们采用一个HashMap来存储账户信息。Account由ATM类通过login登录后使用:
  1. public class ATM {
  2. Account acc;
  3. //作为演示,省略了密码验证
  4. public boolean login( name) {
  5. if (acc != null)
  6. throw new ("Already logged in!");
  7. acc = new Account(name);
  8. return true;
  9. }
  10. public void deposit(float amt) {
  11. acc.deposit(amt);
  12. }
  13. public void withdraw(float amt) throws InsufficientBalanceException {
  14. acc.withdraw(amt);
  15. }
  16. public float getBalance() {
  17. return acc.getBalance();
  18. }
  19. public void logout () {
  20. acc = null;
  21. }
  22. }
下 面是ATMTester,在ATMTester中首先生成了10个ATM实例,然后启动10个线程,同时登录John的账户,先查询余额,然后,再提取余 额的80%,然后再存入等额的款(以维持最终的余额的不变)。按照我们的预想,应该不会发生金额不足的问题。首先看代码:
  1. public class ATMTester {
  2. private static final int NUM_OF_ATM = 10;
  3. public static void main([] args) {
  4. ATMTester tester = new ATMTester();
  5. final thread[] = new [NUM_OF_ATM];
  6. final ATM atm[] = new ATM[NUM_OF_ATM];
  7. for (int i=0; i
  8. atm[i] = new ATM();
  9. thread[i] = new (tester.new Runner(atm[i]));
  10. thread[i].start();
  11. }
  12. }
  13. class Runner implements {
  14. ATM atm;
  15. Runner(ATM atm) {
  16. this.atm = atm;
  17. }
  18. public void run() {
  19. atm.login("John");
  20. //查询余额
  21. float bal = atm.getBalance();
  22. try {
  23. .sleep(1); //模拟人从查询到取款之间的间隔
  24. } catch ( e) {
  25. // ignore it
  26. }
  27. try {
  28. .out.println("Your balance is:" + bal);
  29. .out.println("withdraw:" + bal * 0.8f);
  30. atm.withdraw(bal * 0.8f);
  31. .out.println("deposit:" + bal * 0.8f);
  32. atm.deposit(bal * 0.8f);
  33. } catch (InsufficientBalanceException e1) {
  34. .out.println("余额不足!");
  35. } finally {
  36. atm.logout();
  37. }
  38. }
  39. }
  40. }
运行ATMTester,结果如下(每次运行结果都有所差异):
Your balance is:1000.0
withdraw:800.0
deposit:800.0
Your balance is:1000.0
Your balance is:1000.0
withdraw:800.0
withdraw:800.0
余额不足!
Your balance is:200.0
Your balance is:200.0
Your balance is:200.0
余额不足!
Your balance is:200.0
Your balance is:200.0
Your balance is:200.0
Your balance is:200.0
withdraw:160.0
withdraw:160.0
withdraw:160.0
withdraw:160.0
withdraw:160.0
withdraw:160.0
withdraw:160.0
deposit:160.0
余额不足!
余额不足!
余额不足!
余额不足!
余额不足!
余额不足!
为 什么会出现这样的情况?因为我们这儿是多个ATM同时对同一账户进行操作,比如一个ATM查询出了余额为1000,第二个ATM也查询出了余额1000, 然后两者都期望提取出800,那么只有第1个用户能够成功提出,因为在第1个提出800后,账户真实的余额就只有200了,而第二个用户仍认为余额为 1000。这个问题是由于多个ATM同时对同一个账户进行操作所不可避免产生的后果。要解决这个问题,就必须限制同一个账户在某一时刻,只能由一个ATM 进行操作。如何才能做到这一点?直接通过synchronized关键字可以吗?非常遗憾!因为我们现在需要对整个Account的多个方法进行同步,这 是跨越多个方法的,而synchronized仅能对方法或者代码块进行同步。在下一篇我们将通过编写一个锁对象达到这个目的。
------------------------------------------------
请阅读下篇:

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/374079/viewspace-132138/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/374079/viewspace-132138/

你可能感兴趣的文章
SQL Server 2019中的轻量级性能分析
查看>>
学习MySQL:使用SELECT语句从MySQL服务器查询数据
查看>>
sql聚簇索引和非聚簇索引_使用SQL CREATE INDEX创建聚簇和非聚簇索引
查看>>
如何在SQL Server中索引外键列
查看>>
mysql 如何对表排序_学习MySQL:对表中的数据进行排序和过滤
查看>>
sql azure 语法_将SQL工作负载迁移到Microsoft Azure:规划迁移
查看>>
5000_500
查看>>
同步等待 异步等待_异步等待
查看>>
designmode_designMode
查看>>
api代理提取_提取API
查看>>
php 锚点_使用PHP分配锚点ID
查看>>
css 相同的css属性_CSS属性,内容和L10N
查看>>
v视差 u视差_视差SEO难题
查看>>
pygments_在PHP和WordPress上的Pygments
查看>>
js .has_使用has.js进行JavaScript功能检测
查看>>
javascript 编码_带类JavaScript编码
查看>>
dojo ajax 传参_使用Dojo动画AJAX记录删除
查看>>
unity 施加力量_在空块元素上施加宽度
查看>>
内核标头和开发包_PHP标头和流行的Mime类型
查看>>
preferreds-color-scheme:CSS媒体查询
查看>>