线程同步 在多线程的编程环境下,可能看着没有问题的代码在运行几千上万或者更多次后,出现了一些看着很奇怪的问题,出现这样的问题的原因就是可能会有两个或者更多个线程进入了同一块业务处理代码中导致了判断失效。为了解决这个问题,JAVA引入了同步监视器来解决这个问题。同步监视器的通用方法就是同步代码块,也就是给一块代码加了同步锁。
package cn.test.hf; import java.math.BigDecimal; /** * 模拟取钱操作 */public class RunnableTest implements Runnable { private Account account; // 当前用户想取的钱 private BigDecimal withdrawal; public RunnableTest(Account account, BigDecimal withdrawal) { this.account = account; this.withdrawal = withdrawal; } public void run() { // 判断当前用户取钱的数目是否超出余额 if (this.withdrawal.subtract(this.account.getHaveMoney()).doubleValue() <= 0) { // 取钱之后将账户的余额减少 this.account.setHaveMoney(this.account.getHaveMoney().subtract(this.withdrawal)); System.out.println("当前用户" + Thread.currentThread().getName() + "取出金额" + this.withdrawal + ",取款成功!"); } else { System.out.println("当前用户" + Thread.currentThread().getName() + "取的金额" + this.withdrawal + "超出限制!"); } } public static void main(String[] args) { try { Account account = new Account(); account.setHaveMoney(new BigDecimal(1000)); account.setRemainMoney(new BigDecimal(1000)); RunnableTest r1 = new RunnableTest(account, new BigDecimal("800")); RunnableTest r2 = new RunnableTest(account, new BigDecimal("900")); Thread t1 = new Thread(r1, "张三"); t1.start(); Thread t2 = new Thread(r2, "李四"); t2.start(); // 完成之后再还原 } catch (Exception e) { } }}
在高并发的情况下,张三和李四操作了同一个账户,可能会出现的问题是张三和李四取钱都成功了,那么账户的余额就为负数了。
处理这种问题
方法1、使用synchronized(obj)同步代码块来锁定当前的obj对象,obj就是同步监视器,任何时刻只有一个线程可以获得对同步监视器的锁定,线程操作完后释放对象锁。
代码如下:
public void run() { synchronized (this.account) { // 判断当前用户取钱的数目是否超出余额 if (this.withdrawal.subtract(this.account.getHaveMoney()).doubleValue() <= 0) { // 取钱之后将账户的余额减少 this.account.setHaveMoney(this.account.getHaveMoney().subtract(this.withdrawal)); System.out.println("当前用户" + Thread.currentThread().getName() + "取出金额" + this.withdrawal + ",取款成功!"); } else { System.out.println("当前用户" + Thread.currentThread().getName() + "取的金额" + this.withdrawal + "超出限制!"); } }} 方法二、使用同步方法,同步方法和同步代码块对应,同步方法就是使用synchronized来修饰某个方法,对于synchronized修改的实例方法无须显示指定同步控制器,同步方法的同步监视器就是当前对象,也就是this,不可变类总是线程安全的,可变类不是线程安全的,所以可以通过synchronized来修饰对应的set方法来控制多线程并发访问。
时间: 2024-10-16 21:54:11