java的同步三种方式--银行取钱问题

/*同步方法
对于取钱,当输入要取得钱数,存在计算余额和吐出钱数,由于cpu切换是随机的
在存取之间就有可能存在错误,同时若有好几个人同时取钱,就牵扯到多线程,就要考虑
保护线程,一旦有人进去取钱,其他人都不能进入进行操作,通常可以用
1.用同步方法,用synchronized去修饰方法,例如本例子中用public synchronized void draw(double drawMoney)
2.还可以用同步代码块,synchronized(obj){}去保护线程
3.用lock的方法
*/


第一种方式的例子:

// 这个程序采用的是synchronized方式的锁住线程
/**
 * 账号信息:
 * 
 * **/


class Account{
// 余额
private double balance;
// 构造函数
public  Account(double balance)
{
super();
this.balance = balance;

//super(name);
}
// getter函数
public double getBalance()
{
return balance;
}
// setter函数
public void setBalance(double balance)
{
this.balance = balance;
}
}
/**
 *
 * 取钱的操作方法
 *
 */
class ATM implements Runnable{
private double dMoney;
private Account a;
public ATM(double dMoney, Account a)
{
super();
this.dMoney = dMoney;
this.a = a;
}

Object o = new Object();
public void run()
{
// 采用同步的方式去,控制线程,一旦进入后就不能让其他的线程进入
synchronized(a){
// 如果余款大于取钱的数就操作
if(a.getBalance() >= dMoney)
{
// 输出要取得钱数
System.out.println(Thread.currentThread().getName()+
"取出的钱数"+dMoney);
// 设置余款
a.setBalance(a.getBalance()-dMoney);
// 打印出余款
System.out.println(Thread.currentThread().getName()+
"还剩"+a.getBalance()+"元");

}
else
{
System.out.println(Thread.currentThread().getName()+
"余额不足,还剩下"+a.getBalance());
}
}






}
}
public class drawMoney {



public static void main(String[] args) {


// 账号钱的初始化
Account aa = new Account(1000);
// 取钱的初始化
ATM atm = new ATM(800, aa);
new Thread(atm, "AA").start();
new Thread(atm, "BB").start();


}


}


第二种方式的例子:
class Account1 {
private double balance ;
public Account1(double balance )
{
super();
this.balance = balance ;
}
public double getBalance()
{
return balance;
}
 
public void setBalance(double balance)
{
this.balance = balance;
}
 
//               同步方法
//       取钱
/**
* 同步方法的同步监听器对象:   若该方法是非静态的那么就是this
* 若方法是静态那么就是同步方法所在类的  Class clz  =  Account2.class;(一份字节码)
*/
public synchronized void draw(double drawMoney )
{
// 能取钱的操作函数
if(balance >= drawMoney)
{
// 取出多少钱
System.out.println(Thread.currentThread().getName()+
"取出多少钱"+drawMoney);
try {
Thread.sleep(1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// 设置账户余额还有多少
setBalance(balance - drawMoney);
//           余额还有多少  
System.out.println(Thread.currentThread().getName()+
"账户的余额是:"+getBalance());
}
else{
System.out.println(Thread.currentThread().getName()+
"账户余额不足,余额为:"+getBalance());
}
}
 }
 class  ATM1 implements Runnable{
//      取得钱数  
private double drawMoney;
private Account1 a;
public ATM1(double drawMoney, Account1 a)
{
this.drawMoney = drawMoney;
this.a = a;
}
public void run()
{
 
a.draw(drawMoney);
}
 }
 
public class synchronizedThread {
public static void main(String [] args)
{
Account1 a = new Account1(1000);
ATM1 atm = new ATM1 (800,a);
// 对于相同的账户,不同的人去取钱
new Thread(atm, "AA").start();
new Thread(atm, "BB").start();
new Thread(atm, "CC").start();
}

}


第三种方式:采用lock的方式

/**


* java.util.concurrent.locks.Lock接口
* java.util.concurrent.locks.ReentrantLock类
* ReentrantLock,可重入锁,没有同步监听对象

*  
*  格式:
*  
*   private final ReentrantLock lock= new ReentrantLock();//创建锁的一个对象
*  
*   public void  m(){
*   //进入方法第一件事,上锁
*   lock.lock();//获取锁
*   
*   try{
*   //需要同步的代码
*   }finally{
*   lock.unlock();//解锁,走人
*   }
*   
*   
*   }
*  

*/

import java.util.concurrent.locks.ReentrantLock;

// 创建可重入锁
class Account2 
{
private ReentrantLock lock = new ReentrantLock();
private double balance ;
public Account2(double balance)
{
super();
this.balance = balance ;
}

public double getBalance ()
{
return balance;
}
public void setBalance (double balance)
{
this.balance = balance ; 
}
public void draw2(double drawMoney)
{
lock.lock();
try{


// 能取钱的操作函数
if(balance >= drawMoney)
{
// 取出多少钱
System.out.println(Thread.currentThread().getName()+
"取出多少钱"+drawMoney);
try {
Thread.sleep(1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// 设置账户余额还有多少
setBalance(balance - drawMoney);
//           余额还有多少  
System.out.println(Thread.currentThread().getName()+
"账户的余额是:"+getBalance());
}
else{
System.out.println(Thread.currentThread().getName()+
"账户余额不足,余额为:"+getBalance());
}
}finally{
lock.unlock();
}
}
}


class ATM2 implements Runnable{


private double drawMoney;
private Account2 a;
public   ATM2(Account2 a, double drawMoney)
{
this.a = a;
this.drawMoney = drawMoney;
}
public void run()
{
a.draw2(drawMoney);
}
}


public class lockThread {
public  void main(String []args)
{
Account2 a = new Account2(1000);
ATM2 atm = new ATM2(a, 800);
 
new Thread(atm, "张三").start();
new Thread(atm, "李四").start();
new Thread(atm, "王五").start();
 

}


}


以上三种方式均可以解决同步问题,就个人感觉而言,用lock的方式好些,好理解好用!



好的,您的问题是关于Java多线程的存钱取钱问题。这是一个经典的多线程同步问题,可以通过使用synchronized关键字来实现线程安全。下面是一个简单的示例代码: ```java public class BankAccount { private int balance; public BankAccount(int balance) { this.balance = balance; } public synchronized void deposit(int amount) { balance += amount; System.out.println("Deposit successful. Balance: " + balance); } public synchronized void withdraw(int amount) { if (balance < amount) { System.out.println("Withdraw failed. Insufficient balance."); return; } balance -= amount; System.out.println("Withdraw successful. Balance: " + balance); } } public class Main { public static void main(String[] args) { BankAccount account = new BankAccount(1000); // Create two threads to simulate deposit and withdraw Thread depositThread = new Thread(() -> { for (int i = 0; i < 5; i++) { account.deposit(100); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } }); Thread withdrawThread = new Thread(() -> { for (int i = 0; i < 5; i++) { account.withdraw(200); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } }); depositThread.start(); withdrawThread.start(); } } ``` 在这个示例代码中,我们创建了一个银行账户类BankAccount,并在其中实现了deposit和withdraw方法,并使用synchronized关键字来保证线程安全。 在main方法中,我们创建了两个线程来模拟存款和取款操作,每个线程执行5次操作。我们使用Thread.sleep方法来模拟每个操作之间的间隔,以便更好地观察多线程操作的结果。 当多个线程同时访问BankAccount对象的deposit和withdraw方法时,synchronized关键字可以确保每个方法只能被一个线程访问,从而避免了竞争条件和数据不一致的问题。 希望这个示例代码能够回答您的问题
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值