多线程运行问题
- 各个线程是通过竞争CPU时间而获得运行机会的
- 各线程什么时候得到CPU时间,占用多久,是不可预测的
- 一个正在运行着的线程在什么地方被暂停是不确定的
银行存取款问题
Java
public class Bank {
private String account;// 账号
private int balance;// 账户余额
public Bank(String account, int balance) {
this.account = account;
this.balance = balance;
}
public String getAccount() {
return account;
}
public void setAccount(String account) {
this.account = account;
}
public int getBalance() {
return balance;
}
public void setBalance(int balance) {
this.balance = balance;
}
@Override
public String toString() {
return "Bank [账号=" + account + ", 余额=" + balance + "]";
}
// 存款
public void saveAccount() {
// 可以在不同的位置处添加sleep方法
// 获取当前的账号余额
int balance = getBalance();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// 修改余额,存100元
balance += 100;
// 修改账户余额
setBalance(balance);
// 输出存款后的账户余额
System.out.println("存款后的账户余额为:" + balance);
}
public void drawAccount() {
// 在不同的位置处添加sleep方法
// 获得当前的账户余额
int balance = getBalance();
// 修改余额,取200
balance = balance - 200;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// 修改账户余额
setBalance(balance);
System.out.println("取款后的账户余额:" + balance);
}
}
Java
//存款
public class SaveAccount implements Runnable {
Bank bank;
public SaveAccount(Bank bank) {
this.bank = bank;
}
public void run() {
bank.saveAccount();
}
}
Java
//取款
public class DrawAccount implements Runnable {
Bank bank;
public DrawAccount(Bank bank) {
this.bank = bank;
}
public void run() {
bank.drawAccount();
}
}
Java
public class Test {
public static void main(String[] args) {
// 创建账户,给定余额为1000
Bank bank = new Bank("1001", 1000);
// 创建线程对象
SaveAccount sa = new SaveAccount(bank);
DrawAccount da = new DrawAccount(bank);
Thread save = new Thread(sa);
Thread draw = new Thread(da);
save.start();
draw.start();
try {
draw.join();
save.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(bank);
}
}
通过结果我们可以看到,存款后的余额是正确输出的,然而我们取款200,账户余额却少了300元,如果这发生在现实的ATM机上,后果不堪设想,造成这种状况的原因是线程不同步。一个正在运行着的线程在什么地方被暂停是不确定的,我们在存款100元后假设还没有更改余额,该进程就因为未知原因停止运行,CPU就被取款进程抢占了,这个时候取款方法获得当前的余额为存款之前的余额1000元,然后存款进程继续执行更新操作,并且正确输出了结果,然而取款进程获得的余额为1000元,再取出200元,输出取款后结果就变成了800元。
那么为了保证在存款或取款的时候,不允许其他线程对账户余额进行操作,我们要将Bank对象进行锁定,使用关键字synchronized实现
同步
synchronized关键字用在
- 成员方法
- 静态方法
- 语句块
public synchronized void saveAccount(){}
public static synchronized void saveAccount(){}
synchronized(obj){……}