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

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

首先,模拟一个场景,多个线程同时操纵一个账户(Account),有些进行取钱操作,有些进行存钱操作。

每次取钱金额为500,不足500无法取钱。
每次存钱金额100,账户余额大于等于500无法存钱。

取钱时金额不足,取钱的线程会等待,等其他存钱的线程存够500则可以继续取钱。
存钱时账户已经有500,则存钱的线程会等待,等其他取钱的线程取走钱后可以继续存钱。

首先定义一个账户类
账户有个withdraw方法,用来对账户进行取500元的操作。
当账户余额不足,则取钱的线程会等待。

账户有个deposit方法,用来对账户进行存100元钱的操作。
当账户余额已达500,则存钱的线程会等待。

class Account {
        int balence = 500;

        synchronized void withdraw(int amount) throws InterruptedException {
            while (this.balence < amount) {
                System.out.println("线程 " + Thread.currentThread().getName() + "在尝试取钱 ");
                System.out.println("尝试取钱 " + amount + ", 余额为 " + this.balence+"无法取钱");
                wait();
            }
            this.balence -= amount;
            notifyAll();//若成功取钱,则通知其他线程取消等待
            System.out.println("取钱 " + amount + ", 余额为 " + this.balence);
        }

        synchronized void deposit(int amount) throws InterruptedException {
            while (this.balence >= 500) {
                System.out.println("线程 " + Thread.currentThread().getName() + "在尝试存钱 ");
                System.out.println("尝试存钱 " + amount + ", 余额为 " + this.balence+"无法存钱");
                wait();
            }
            this.balence += amount;
            notifyAll();//若成功存钱,则通知其他线程取消等待
            System.out.println("存钱 " + amount + ", 余额为 " + this.balence);
        }
    }

初始时账户中有500余额。

然后定义一个取钱操作
一旦放入一个线程中启动,线程一直会对这个账户进行取钱操作

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

再定义一个存钱操作
一旦放入一个线程中启动,线程一直会对这个账户进行存钱操作

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

再开启多个线程同时操作账户进行取钱和存钱的操作,再main函数中调用。

    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();
    }

完整的代码如下

package com.basic.thread;

public class ThreadTest1 {

    Account account = new Account();// 线程安全的账户

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

    class Account {
        int balence = 500;

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

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

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

    Runnable deposit = new Runnable() {
        @Override
        public void run() {
            while (true) {
                try {
                    account.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();
    }
}

运行这个程序,查看console输出的信息:

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

通过结果可以看到,同时操作的账户能正确地处理多个存取操作。

这里注意到,Account的deposit与withdraw方法使用了同步方法,并通过wait-notify进行线程间通信,保证了线程安全。

线程安全问题出现的情况请查看下一篇

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

猜你喜欢

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