Java: 简单模拟多线程访问同样变量导致的问题

简单模拟多线程访问同样变量导致的问题,需要使用Transaction控制,或加锁。
package  practice;

public   class  RyanAndMonicaJob  implements  Runnable {
    
private BankAccount account = new BankAccount();
    
public static void main(String[] args){
        RyanAndMonicaJob runner 
= new RyanAndMonicaJob();
        Thread one 
= new Thread(runner);
        Thread two 
= new Thread(runner);
        one.setName(
"Ryan");
        two.setName(
"Monica");
        one.start();
        two.start();
    }

    
    
public void run(){
        
for(int i=0; i< 10; i++){
            withdraw(
30);
        }

        
if(account.getBalance()<0){
            System.out.println(
"the account is overdrawed!");
        }

    }

    
private void withdraw(int amount){
        
if(account.getBalance()>amount){
            
try{
                System.out.println(Thread.currentThread().getName() 
+" is going to sleep.");
                Thread.sleep(
500);
            }
catch(Exception e){
                e.printStackTrace();
            }

            System.out.println(Thread.currentThread().getName() 
+ " woke up");
            account.withdraw(amount);
            System.out.println(
"after " + Thread.currentThread().getName() + " withdraw, the account is: " + account.getBalance());
        }
else{
            System.out.println(
"sorry " + Thread.currentThread().getName() + " the money is : " + account.getBalance());
        }

    }

}


package  practice;

public   class  BankAccount  {
    
int balance = 200;
    
public int getBalance(){
        
return balance;
    }

    
public void withdraw(){
        balance 
= balance - 150;
    }

}

修正其中的问题方法一:把其中的方法作为一个Transaction

package  practice;

public   class  RyanAndMonicaJob  implements  Runnable {
    
private BankAccount account = new BankAccount();
    
public static void main(String[] args){
        RyanAndMonicaJob runner 
= new RyanAndMonicaJob();
        Thread one 
= new Thread(runner);
        Thread two 
= new Thread(runner);
        one.setName(
"Ryan");
        two.setName(
"Monica");
        one.start();
        two.start();
    }

    
    
public void run(){
        
for(int i=0; i< 10; i++){
            withdraw(
30);
        }

        
if(account.getBalance()<0){
            System.out.println(
"the account is overdrawed!");
        }

    }

    
private synchronized void withdraw(int amount){
        
if(account.getBalance()>amount){
            
try{
                System.out.println(Thread.currentThread().getName() 
+" is going to sleep.");
                Thread.sleep(
500);
            }
catch(Exception e){
                e.printStackTrace();
            }

            System.out.println(Thread.currentThread().getName() 
+ " woke up");
            account.withdraw(amount);
            System.out.println(
"after " + Thread.currentThread().getName() + " withdraw, the account is: " + account.getBalance());
        }
else{
            System.out.println(
"sorry " + Thread.currentThread().getName() + " the money is : " + account.getBalance());
        }

    }

}

其中只增加了一个关键字: synchronized 同步方法非常简单,这样方法就作为了原子来执行。

但是,如果只有这个方法访问account,那么不会出现问题,如果还有方法需要访问account,那么需要使用Object key 才有效了,否则即便这个方法封锁了自己,仍然可能获得错误的account而执行错误的操作。

如下的例子导致了“Lost Update”
package  practice;

public   class  TestSync  implements  Runnable {
    
private int balance;
    
    
public void run(){
        
for(int i=0;i<5000;i++){
            increaseBalance();
        }

    }

    
    
private void increaseBalance(){
        System.out.println(Thread.currentThread().getName() 
+ ++balance);
    }

}
package  practice;

public   class  TestSyncTest  {
    
public static void main(String[] args){
        TestSync runner 
= new TestSync();
        Thread one 
= new Thread(runner);
        Thread two 
= new Thread(runner);
        one.setName(
"A");
        two.setName(
"B");
        one.start();
        two.start();
    }

}


在执行过程中是很有出错概率的。解决方法还是一样的:在该increaseBalance()上加上synchronized关键字。
出现的适用范围也是一样,只有歌操作balance的的方法是有效的,但是如果还有其它线程用不同方法操作balance就会遇到问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值