线程同步(二)—synchronized

本文通过模拟银行取钱的例子,详细解释了Java中如何使用synchronized关键字来保护多线程共享数据的安全,确保数据在修改时不会出现并发错误。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


当多线程共享一个数据时候,就会容易因为编程不对而导致出现错误。比如,两个线程对一个数据进行修改,由于线程调度的不确定性,导致出现错误。所以,java引进了synchronized进行对共享数据的保护,确保在一个线程在对数据进行修改处理的时候,其他线程不能对该数据进行修改访问。

   实例:模拟 银行取钱

1.实体类对象:Account.java

 

       package thread.account;

public class Account
{
	private String accountNo;
	private double balance;
public Account(){}

	public Account(String accountNo , double balance)
	{
		this.accountNo = accountNo;
		this.balance = balance;
	}

	public void setAccountNo(String accountNo)
	{
		this.accountNo = accountNo;
	}
	public String getAccountNo()
	{
		 return this.accountNo;
	}

	public double getBalance()
	{
		 return this.balance;
	}
//同步方法,使方法线程方法安全,不被多个线程同时访问修改
	public synchronized void draw(double drawAmount)
	{
		//账户余额大于取钱数目
		if (balance >= drawAmount)
		{
			//吐出钞票
			System.out.println(Thread.currentThread().getName() + 
				"取钱成功!吐出钞票:" + drawAmount);
			try
			{
				Thread.sleep(1);			
			}
			catch (InterruptedException ex)
			{
				ex.printStackTrace();
			}
			//修改余额
			balance -= drawAmount;
			System.out.println("\t余额为: " + balance);
		}
		else
		{
			System.out.println(Thread.currentThread().getName() +
				"取钱失败!余额不足!");
		}
	}

	public int hashCode()
	{
		return accountNo.hashCode();
	}
	public boolean equals(Object obj)
	{
		if (obj != null && obj.getClass() == Account.class)
		{
			Account target = (Account)obj;
			return target.getAccountNo().equals(accountNo);
		}
		return false;
	}
}
 

 

 2.  线程对象 DrawThread.java


 package thread.account;

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()
	{
		account.draw(drawAmount);
	}
}

 3.  测试 TestDraw.java


 package thread.account;
public class TestDraw
{
    public static void main(String[] args) 
    {
		//创建一个账户
		Account acct = new Account("1234567" , 1000);
		//模拟两个线程对同一个账户取钱
		new DrawThread("甲" , acct , 800).start();
		new DrawThread("乙" , acct , 800).start();
    }
}

那么synchronized是如何释放资源的呢?答:所有对象都自动含有单一的锁,JVM负责跟踪对象被加锁的次数。如果一个对象被解锁,其计数变为0。在任务(线程)第一次给对象加锁的时候,计数变为1。每当这个相同的任务(线程)在此对象上获得锁时,计数会递增。每当任务离开一个synchronized方法,计数递减,当计数为0的时候,锁被完全释放,此时别的任务就可以使用此资源。


注:在jdk1.5之后,java提供了Lock进行同步处理,Lock能实现synchronized的所有功能,而且性能比synchronized高,我接下来继续讲Lock 



 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值