Java多线程同步1——使用synchronized 代码块

关于多线程同步问题我们可以借用一个银行取钱的实例来说明问题。

在这里我们简单的建立一个类来代表银行账户,代码如下

public class Account {

// 账号

private String accountNo;

//余额

private double balance;

public Account(){}

// 构造器

public Account(String accountNo , double balance)

{

this.accountNo = accountNo;

this.balance = balance;

}

// accountNo的setter和getter方法

public void setAccountNo(String accountNo)

{

this.accountNo = accountNo;

}

public String getAccountNo()

{

return this.accountNo;

}

// balance的setter和getter方法

public void setBalance(double balance)

{

this.balance = balance;

}

public double getBalance()

{

return this.balance;

}

// 下面两个方法根据accountNo来重写hashCode()和equals()方法

public int hashCode()

{

return accountNo.hashCode();

}

public boolean equals(Object obj)

{

if(this == obj)

return true;

if (obj !=null

&& obj.getClass() == Account.class)

{

Account target = (Account)obj;

return target.getAccountNo().equals(accountNo);

}

return false;

}

}


建立一个取钱的线程类

public class DrawThread extends Thread

{

private Account account;

private double drawAmount;

public DrawThread(String name , Account account

, double drawAmount)

{

super(name);

this.account = account;

this.drawAmount = drawAmount;

}

public void run()

{

if (account.getBalance() >= drawAmount)

{

System.out.println(getName()

+ "取钱成功!吐出钞票" + drawAmount);

try

{

Thread.sleep(1);

}

catch (InterruptedException ex)

{

ex.printStackTrace();

}

account.setBalance(account.getBalance() - drawAmount);

System.out.println("\t余额为:" + account.getBalance());

}

else

{

System.out.println(getName() + "取钱失败!余额不足");

}

}

}


在建立一个测试类模仿2个人对同一个账户进行取钱

public class DrawTest

{

public static void main(String[] args)

{

Account acct = new Account("1234567" , 1000);

new DrawThread("甲" , acct , 800).start();

new DrawThread("乙" , acct , 800).start();

}

}

运行结果有可能出现如下图所示的情况


Java多线程同步1——使用synchronized 代码块_第1张图片


问题来了:账户余额只有1000时取出了1600块,而且账户余额出现了负值,这不是我们希望得到的结果。


这是因为run()方法的方法体不具备同步安全性——程序中有两个并发线程在修改Account对象,

为了解决这个问题,java多线程引入了同步监视器来解决这个问题,使用同步监视器的通用方法就是同步代码块。

synchronized (obj){

}

上面语法格式中的synchronized括号里面的obj就是同步监视器,上面代码的含义是:线程开始执行

同步之前,必须先获得同步监视器的锁定
将上面的代码做如下修改


public class DrawThread extends Thread

{

private Account account;

private double drawAmount;

public DrawThread(String name , Account account

, double drawAmount)

{

super(name);

this.account = account;

this.drawAmount = drawAmount;

}

public void run()

{

synchronized (account)

{

if (account.getBalance() >= drawAmount)

{

System.out.println(getName()

+ "取钱成功!吐出钞票:" + drawAmount);

try

{

Thread.sleep(1);

}

catch (InterruptedException ex)

{

ex.printStackTrace();

}

account.setBalance(account.getBalance() - drawAmount);

System.out.println("\t余额为: " + account.getBalance());

}

else

{

System.out.println(getName() + "取钱失败!余额不足");

}

}

}

}

运行代码得到如下结果:


你可能感兴趣的:(Java多线程同步1——使用synchronized 代码块)