ITPub博客

首页 > Linux操作系统 > Linux操作系统 > [转载]Java多线程同步教程--BusyFlag或Locknbsp;(上)

[转载]Java多线程同步教程--BusyFlag或Locknbsp;(上)

原创 Linux操作系统 作者:dinner1007 时间:2019-02-24 07:12:05 0 删除 编辑
Java多线程同步教程--BusyFlag或Locknbsp;(上)
Java语言内置了synchronized关键字用于对多线程进行同步,大大方便了Java中多线程程序的编写。但是仅仅使用 synchronized关键字还不能满足对多线程进行同步的所有需要。大家知道,synchronized仅仅能够对方法或者代码块进行同步,如果我们 一个应用需要跨越多个方法进行同步,synchroinzed就不能胜任了。在C++中有很多同步机制,比如信号量、互斥体、临届区等。在Java中也可 以在synchronized语言特性的基础上,在更高层次构建这样的同步工具,以方便我们的使用。
当前,广为使用的是由Doug Lea编写的一个Java中同步的工具包,可以在这儿了解更多这个包的详细情况:
http://gee.cs.oswego.edu/dl/classes/EDU/oswego/cs/dl/util/concurrent/intro.html
该工具包已经作为JSR166正处于JCP的控制下,即将作为JDK1.5的正式组成部分。本文并不打算详细剖析这个工具包,而是对多种同步机制的一个介 绍,同时给出这类同步机制的实例实现,这并不是工业级的实现。但其中会参考Doug Lea的这个同步包中的工业级实现的一些代码片断。
本例中还沿用上篇中的Account类,不过我们这儿编写一个新的ATM类来模拟自动提款机,通过一个ATMTester的类,生成10个ATM线程,同时对John账户进行查询、提款和存款操作。Account类做了一些改动,以便适应本篇的需要:

  1. import java.util.HashMap;
  2. import java.util.Map;
  3. class Account {
  4. String name;
  5. //float amount;
  6. //使用一个Map模拟持久存储
  7. static Map storage = new HashMap();
  8. static {
  9. storage.put("John", new Float(1000.0f));
  10. storage.put("Mike", new Float(800.0f));
  11. }
  12. public Account(String 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 = ((Float)storage.get(name)).floatValue();
  19. storage.put(name, new Float(amount + amt));
  20. }
  21. public synchronized void withdraw(float amt) throws InsufficientBalanceException {
  22. float amount = ((Float)storage.get(name)).floatValue();
  23. if (amount >= amt)
  24. amount -= amt;
  25. else
  26. throw new InsufficientBalanceException();
  27. storage.put(name, new Float(amount));
  28. }
  29. public float getBalance() {
  30. float amount = ((Float)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(String name) {
  5. if (acc != null)
  6. throw new IllegalArgumentException("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(String[] args) {
  4. ATMTester tester = new ATMTester();
  5. final Thread thread[] = new Thread[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 Thread(tester.new Runner(atm[i]));
  10. thread[i].start();
  11. }
  12. }
  13. class Runner implements Runnable {
  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. Thread.sleep(1); //模拟人从查询到取款之间的间隔
  24. } catch (InterruptedException e) {
  25. // ignore it
  26. }
  27. try {
  28. System.out.println("Your balance is:" + bal);
  29. System.out.println("withdraw:" + bal * 0.8f);
  30. atm.withdraw(bal * 0.8f);
  31. System.out.println("deposit:" + bal * 0.8f);
  32. atm.deposit(bal * 0.8f);
  33. } catch (InsufficientBalanceException e1) {
  34. System.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仅能对方法或者代码块进行同步。在下一篇我们将通过编写一个锁对象达到这个目的。

------------------------------------------------
请阅读下篇:Java多线程同步教程--BusyFlag或Lock (下)

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

请登录后发表评论 登录
全部评论

注册时间:2018-08-23

  • 博文量
    1714
  • 访问量
    1477718