线程并发问题的解决方案--线程同步锁定-锁对对象

模拟银行取存款

        ==================线程不安全的===============================================

1.先弄一个银行账户对象,封装了存取插钱的方法:

package com.test.threadDemo2;

/**
 * 银行账户
 * @author Administrator
 *
 */
public class Acount {
    private int count=0;
    
    /**
     * 存钱
     * @param money
     */
    public void addAcount(String name,int money) {
        17             // 存钱
            count += money;
            System.out.println(name+"...存入:"+money+"..."+Thread.currentThread().getName());
            SelectAcount(name);
22     }
    
    /**
     * 取钱
     * @param money
     */
    public void subAcount(String name,int money) {
        30             // 先判断账户现在的余额是否够取钱金额
            if(count-money < 0){  
                System.out.println("账户余额不足!"); 
                return;  
            } 
            // 取钱
            count -= money;
            System.out.println(name+"...取出:"+money+"..."+Thread.currentThread().getName());
            SelectAcount(name);
40     }
    
    /**
     * 查询余额
     */
    public void SelectAcount(String name) {
        System.out.println(name+"...余额:"+count);
    }


public static void main(String[] args) {
        
        // 开个银行帐号
        Account account = new Account();
        // 开银行帐号之后银行给张银行卡
        Card card = new Card("card",account);
        // 开银行帐号之后银行给张存折
        Paper paper = new Paper("存折",account);
        
        Thread thread1 = new Thread(card);
        Thread thread2 = new Thread(paper);
        
        thread1.start();
        thread2.start();            
    }
}



2.编写银行卡对象

package com.test.threadDemo2;
/**
 * 银行卡负责存钱
 * @author Administrator
 *
 */
public class Card implements Runnable{
    private String name;
    private Account account = new Account();
    
    public Card(String name,Account account) {
        this.account = account;
        this.name = name;
    }
    
    @Override
    public void run() {
        
        while(true) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            account.addAccount(name,100);26         }
    }
    
}

3.编写存折对象

package com.test.threadDemo2;
/**
 * 存折负责取钱
 * @author Administrator
 *
 */
public class Paper implements Runnable{
    private String name;
    private Account account = new Account();
    
    public Paper(String name,Account account) {
        this.account = account;
        this.name = name;
    }
    
    @Override
    public void run() {
        while(true) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            account.subAccount(name,50);
        }
        
    }

}

由于对存取钱的账户没有锁定,导致线程不安全的,会产生并发问题。造成,账户余额为负。
在这里插入图片描述
解决措施

==============================================以下是线程安全的===================


同步代码块
package com.test.threadDemo2;

/**
 * 银行账户
 * @author Administrator
 *
 */
public class Acount {
    private int count=0;
    
    /**
     * 存钱
     * @param money
     */
    public void addAcount(String name,int money) {
        synchronized(this) {
            // 存钱
            count += money;
            System.out.println(name+"...存入:"+money+"..."+Thread.currentThread().getName());
            SelectAcount(name);
        }
    }
    
    /**
     * 取钱
     * @param money
     */
    public void subAcount(String name,int money) {
        synchronized(this) {
            // 先判断账户现在的余额是否够取钱金额
            if(count-money < 0){  
                System.out.println("账户余额不足!"); 
                return;  
            } 
            // 取钱
            count -= money;
            System.out.println(name+"...取出:"+money+"..."+Thread.currentThread().getName());
            SelectAcount(name);
        }
    }
    
    /**
     * 查询余额
     */
    public void SelectAcount(String name) {
        System.out.println(name+"...余额:"+count);
    }
}

同步方法块

package com.test.threadDemo2;
/**
 * 银行账户
 * @author Administrator
 *
 */
public class Acount {
    private int count;
    
    /**
     * 存钱
     * @param money
     */
    public synchronized void addAcount(String name,int money) {
            // 存钱
            count += money;
            System.out.println(name+"...存入:"+money);
    }
    
    /**
     * 取钱
     * @param money
     */
    public synchronized void subAcount(String name,int money) {
            // 先判断账户现在的余额是否够取钱金额
            if(count-money < 0){  
                System.out.println("账户余额不足!");  
                return;  
            } 
            // 取钱
            count -= money;
            System.out.println(name+"...取出:"+money);
    }
    
    /**
     * 查询余额
     */
    public void SelectAcount(String name) {
        System.out.println(name+"...余额:"+count);
    }
}

3 使用同步锁:
account 类创建私有的 ReetrantLock 对象,调用 lock() 方法,同步执行体执行完毕之后,需要用 unlock() 释放锁。

package com.test.threadDemo2;

import java.util.concurrent.locks.ReentrantLock;

/**
 * 银行账户
 * @author Administrator
 *
 */
public class Acount {
    private int count;
    private ReentrantLock lock = new ReentrantLock();
    
    /**
     * 存钱
     * @param money
     */
    public void addAcount(String name,int money) {
        lock.lock();
        try{
            // 存钱
            count += money;
            System.out.println(name+"...存入:"+money);
        }finally {
            lock.unlock();
        }
    }
    
    /**
     * 取钱
     * @param money
     */
    public void subAcount(String name,int money) {
        lock.lock();
        try{
            // 先判断账户现在的余额是否够取钱金额
            if(count-money < 0){  
                System.out.println("账户余额不足!");  
                return;  
            } 
            // 取钱
            count -= money;
            System.out.println(name+"...取出:"+money);
        }finally {
            lock.unlock();
        }
    }
    
    /**
     * 查询余额
     */
    public void SelectAcount(String name) {
        System.out.println(name+"...余额:"+count);
    }
}

二、死锁

当线程需要同时持有多个锁时,有可能产生死锁。考虑如下情形:

线程 A 当前持有互斥所锁 lock1,线程 B 当前持有互斥锁 lock2。

接下来,当线程 A 仍然持有 lock1 时,它试图获取 lock2,因为线程 B 正持有 lock2,因此线程 A 会阻塞等待线程 B 对 lock2 的释放。

如果此时线程 B 在持有 lock2 的时候,也在试图获取 lock1,因为线程 A 正持有 lock1,因此线程 B 会阻塞等待 A 对 lock1 的释放。

二者都在等待对方所持有锁的释放,而二者却又都没释放自己所持有的锁,这时二者便会一直阻塞下去。这种情形称为死锁。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值