系列的几篇文章介绍一下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进行线程间通信,保证了线程安全。
线程安全问题出现的情况请查看下一篇