Java中的线程不完全问题:
- 当多线程并发访问临界资源时,如果破坏了原子操作,可能会造成数据不一致。
- 临界资源:共享资源(同一对象),一次仅允许一个线程使用,才可保证其正确性。
- 原子操作:不可分割的多步操作,被视作一个整体,其步骤和顺序不可打乱或缺省。
举例子:最常见的例子就是银行取存款问题。
以下例子就是根据现实中银行卡的子母卡,丈夫,与妻子各一张卡为子母卡,同时取款会遇到的线程安全问题。
这里给出的解决方案是用同步代码块
synchronized(锁对象){
执行同步的代码块
}
public class TestSynchronized {
public static void main(String[] args) {
Account acc = new Account("6002","1234",2000); // 创建一个任务
Thread husband = new Thread(new Husband(acc),"丈夫");//将任务加入丈夫进程
Thread wife = new Thread(new Wife(acc),"妻子");//将任务加入妻子进程
husband.start();// 执行丈夫进程
wife.start();// 执行妻子进程
}
}
class Wife implements Runnable{
Account acc; //账户对象的引用
public Wife(Account acc) {
this.acc = acc;
}
public void run() {
this.acc.widthdrawal("6002", "1234", 1200); //掉用取款方法
}
}
class Husband implements Runnable{
Account acc;
public Husband(Account acc) {
this.acc = acc;
}
public void run() {
this.acc.widthdrawal("6002", "1234", 1200); //掉用取款方法
}
}
class Account{
String cardNo;
String password;
double banlance;
public Account(String cardNo, String password, double banlance) {
this.cardNo = cardNo;
this.password = password;
this.banlance = banlance;
}
//取款
public void widthdrawal(String no,String pwd,double money) {
synchronized(this) {
System.out.println(Thread.currentThread().getName()+"正在读卡...");
if(no.equals(this.cardNo) && pwd.equals(this.password)) {
System.out.println(Thread.currentThread().getName()+"验证成功...");
if(money <= this.banlance) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
this.banlance = this.banlance-money;
System.out.println(Thread.currentThread().getName()+"取款成功!当前余额为:" + this.banlance);
}else {
System.out.println("当前卡内余额不足!");
}
}else {
System.out.println("银行卡密码错误");
}
}
}
}