Java基础知识系列 多线程基础之二 线程安全

系列的几篇文章介绍一下Java语言的多线程的使用。

上一篇Java基础知识系列 多线程基础之一

已经实现了一个账户(Account) ,可以供多个线程同时进行取钱和存钱的操作。

本次将定义一个差不多的账户类,但是本次的这个账号在多个线程同时操作会带来线程安全的问题。

将账户类修改为下面的形式

    class AccountUnsafe {
        int balence = 500;

        void withdraw(final int amount) throws InterruptedException {
            while (this.balence < amount) {
                System.out.println("线程 " + Thread.currentThread().getName() + "在尝试取钱 ");
                System.out.println("尝试取钱 " + amount + ", 余额为 " + this.balence+"无法取钱");
                Thread.sleep(100);
            }
            this.balence -= amount;
            System.out.println("取钱 " + amount + ", 余额为 " + this.balence);
        }

        void deposit(final int amount) throws InterruptedException {
            while (this.balence >= 500) {
                System.out.println("线程 " + Thread.currentThread().getName() + "在尝试存钱 ");
                System.out.println("尝试存钱 " + amount + ", 余额为 " + this.balence+"无法取钱");
                Thread.sleep(100);
            }
            this.balence += amount;
            System.out.println("存钱 " + amount + ", 余额为 " + this.balence);
        }
    }

同样,开始余额为500。

定义一个取钱方法withdraw,每次取500出来,如果余额不足则不会取钱。

定义一个存钱方法deposit,每次存100元,如果余额大于等于500则不会存钱。

注意,这次withdraw和deposit并不是同步(synchronized)的。

如果余额不满足条件,则该线程睡眠100毫秒,以给其他线程以执行的机会,否则可能某一个线程一直在取钱。其它线程无机会执行。

取钱的线程和存钱的线程与之前定义一样

    Runnable withdraw = new Runnable() {
        @Override
        public void run() {
            try {
                while (true) {
                    accountUnsafe.withdraw(500);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    };

    Runnable deposit = new Runnable() {
        @Override
        public void run() {
            while (true) {
                try {
                    accountUnsafe.deposit(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    };

每当启动一个线程进行取钱,则该线程会一直取钱。
每当启动一个线程存钱,则该线程一直存钱。

完整代码如下:

package com.basic.thread;

public class ThreadTest2 {

    AccountUnsafe accountUnsafe = new AccountUnsafe();// 线程不安全的账户

    public static void main(String[] args) {
        new ThreadTest2().accountTest();
    }

    class AccountUnsafe {
        int balence = 500;

        void withdraw(final int amount) throws InterruptedException {
            while (this.balence < amount) {
                System.out.println("线程 " + Thread.currentThread().getName() + "在尝试取钱 ");
                System.out.println("尝试取钱 " + amount + ", 余额为 " + this.balence);
                Thread.sleep(100);
            }
            this.balence -= amount;
            System.out.println("取钱 " + amount + ", 余额为 " + this.balence+"无法取钱");
        }

        void deposit(final int amount) throws InterruptedException {
            while (this.balence >= 500) {
                System.out.println("线程 " + Thread.currentThread().getName() + "在尝试存钱 ");
                System.out.println("尝试存钱 " + amount + ", 余额为 " + this.balence+"无法取钱");
                Thread.sleep(100);
            }
            this.balence += amount;
            System.out.println("存钱 " + amount + ", 余额为 " + this.balence);
        }
    }

    Runnable withdraw = new Runnable() {
        @Override
        public void run() {
            try {
                while (true) {
                    accountUnsafe.withdraw(500);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    };

    Runnable deposit = new Runnable() {
        @Override
        public void run() {
            while (true) {
                try {
                    accountUnsafe.deposit(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    };

    void accountTest() {
        Thread t1 = new Thread(this.withdraw);
        Thread t11 = new Thread(this.withdraw);
        Thread t12 = new Thread(this.withdraw);
        Thread t13 = new Thread(this.withdraw);
        Thread t14 = new Thread(this.withdraw);
        Thread t2 = new Thread(this.deposit);
        Thread t21 = new Thread(this.deposit);
        Thread t22 = new Thread(this.deposit);
        Thread t23 = new Thread(this.deposit);
        Thread t24 = new Thread(this.deposit);
        t1.start();
        t11.start();
        t12.start();
        t13.start();
        t14.start();
        t2.start();
        t21.start();
        t22.start();
        t23.start();
        t24.start();
    }
}

运行程序,查看控制台输出:

//省略以上部分
线程 Thread-0在尝试取钱 
尝试取钱 500, 余额为 400无法取钱
存钱 100, 余额为 400
存钱 100, 余额为 300
存钱 100, 余额为 300
线程 Thread-6在尝试存钱 
存钱 100, 余额为 300
线程 Thread-9在尝试存钱 
尝试存钱 100, 余额为 500无法取钱
线程 Thread-1在尝试取钱 
尝试取钱 500, 余额为 500无法取钱
存钱 100, 余额为 300
线程 Thread-7在尝试存钱 
尝试存钱 100, 余额为 500无法取钱
尝试存钱 100, 余额为 500无法取钱
//省略以下部分

可以看到,出现了连续存钱100但是账户余额均为300的现象。
出现了账户金额不正常的现象。

猜你喜欢

转载自blog.csdn.net/thezprogram/article/details/81275345