zoukankan      html  css  js  c++  java
  • 100个线程同时向一个银行账户中存入1元钱

    下面的例子演示了100个线程同时向一个银行账户中存入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
    /**
     * 银行账户
     * @author 骆昊
     *
     */
    public class Account {
        private double balance;     // 账户余额
     
        /**
         * 存款
         * @param money 存入金额
         */
        public void deposit(double money) {
            double newBalance = balance + money;
            try {
                Thread.sleep(10);   // 模拟此业务需要一段处理时间
            }
            catch(InterruptedException ex) {
                ex.printStackTrace();
            }
            balance = newBalance;
        }
     
        /**
         * 获得账户余额
         */
        public double getBalance() {
            return balance;
        }
    }
    • 存钱线程类:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    /**
     * 存钱线程
     * @author 骆昊
     *
     */
    public class AddMoneyThread implements Runnable {
        private Account account;    // 存入账户
        private double money;       // 存入金额
     
        public AddMoneyThread(Account account, double money) {
            this.account = account;
            this.money = money;
        }
     
        @Override
        public void run() {
            account.deposit(money);
        }
     
    }
    • 测试类:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
     
    public class Test01 {
     
        public static void main(String[] args) {
            Account account = new Account();
            ExecutorService service = Executors.newFixedThreadPool(100);
     
            for(int i = 1; i <= 100; i++) {
                service.execute(new AddMoneyThread(account, 1));
            }
     
            service.shutdown();
     
            while(!service.isTerminated()) {}
     
            System.out.println("账户余额: " + account.getBalance());
        }
    }

    在没有同步的情况下,执行结果通常是显示账户余额在10元以下,出现这种状况的原因是,当一个线程A试图存入1元的时候,另外一个线程B也能够进入存款的方法中,线程B读取到的账户余额仍然是线程A存入1元钱之前的账户余额,因此也是在原来的余额0上面做了加1元的操作,同理线程C也会做类似的事情,所以最后100个线程执行结束时,本来期望账户余额为100元,但实际得到的通常在10元以下(很可能是1元哦)。解决这个问题的办法就是同步,当一个线程对银行账户存钱时,需要将此账户锁定,待其操作完成后才允许其他的线程进行操作,代码有如下几种调整方案:

    • 在银行账户的存款(deposit)方法上同步(synchronized)关键字
    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
    /**
     * 银行账户
     * @author 骆昊
     *
     */
    public class Account {
        private double balance;     // 账户余额
     
        /**
         * 存款
         * @param money 存入金额
         */
        public synchronized void deposit(double money) {
            double newBalance = balance + money;
            try {
                Thread.sleep(10);   // 模拟此业务需要一段处理时间
            }
            catch(InterruptedException ex) {
                ex.printStackTrace();
            }
            balance = newBalance;
        }
     
        /**
         * 获得账户余额
         */
        public double getBalance() {
            return balance;
        }
    }
    • 在线程调用存款方法时对银行账户进行同步
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    /**
     * 存钱线程
     * @author 骆昊
     *
     */
    public class AddMoneyThread implements Runnable {
        private Account account;    // 存入账户
        private double money;       // 存入金额
     
        public AddMoneyThread(Account account, double money) {
            this.account = account;
            this.money = money;
        }
     
        @Override
        public void run() {
            synchronized (account) {
                account.deposit(money);
            }
        }
     
    }
    • 通过Java 5显示的锁机制,为每个银行账户创建一个锁对象,在存款操作进行加锁和解锁的操作
    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
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
     
    /**
     * 银行账户
     *
     * @author 骆昊
     *
     */
    public class Account {
        private Lock accountLock = new ReentrantLock();
        private double balance; // 账户余额
     
        /**
         * 存款
         *
         * @param money
         *            存入金额
         */
        public void deposit(double money) {
            accountLock.lock();
            try {
                double newBalance = balance + money;
                try {
                    Thread.sleep(10); // 模拟此业务需要一段处理时间
                }
                catch (InterruptedException ex) {
                    ex.printStackTrace();
                }
                balance = newBalance;
            }
            finally {
                accountLock.unlock();
            }
        }
     
        /**
         * 获得账户余额
         */
        public double getBalance() {
            return balance;
        }
    }

    按照上述三种方式对代码进行修改后,重写执行测试代码Test01,将看到最终的账户余额为100元。当然也可以使用Semaphore或CountdownLatch来实现同步

  • 相关阅读:
    (转)eclipse安装jetty
    (转)Java compiler level does not match解决方法
    (转)关于eclipse的TestNG的插件安装方法
    win7 远程桌面连接过程
    (转)IntelliJ IDEA 破解方法
    (转) Eclipse Maven 编译错误 Dynamic Web Module 3.1 requires Java 1.7 or newer 解决方案
    (转)@ContextConfiguration注解说明
    (转)java中/r与/n还有/r/n的区别
    (转)eclipse导入Gradle项目
    tomcat架构分析(valve机制)
  • 原文地址:https://www.cnblogs.com/duanqiao123/p/9196722.html
Copyright © 2011-2022 走看看