java基础:线程互斥


引子

由于多线程共享同一资源(临界资源),使得多线程程序结果会有不确定性。

怎么解决不确定性呢?以下两种方式可以部分控制不确定性:

线程互斥

线程同步

在熟悉一下两个概念:

临界区:用synchronized标记的代码段

临界资源:被临界区竞争的访问的资源

线程互斥

锁机制

线程互斥是使用锁机制来实现的,来看看锁机制:

  1. 标记访问共享资源的代码段Java就是用synchronized来标记代码段的,synchronized是个关键字),指明这段代码将作为一个整体以原子方式来访问共享资源;

  2. 给被访问的资源关联上一把锁;

  3. 当标记的的代码段(临界区)访问共享资源(临界资源)前,首先必须获得对象关联的锁;获得锁后将锁锁闭(lock),并开始实施访问;在标记的代码段访问结束后,释放锁;然后别的代码段就可以访问这个资源了。

  4. 只有对象才有锁基本数据类型没有锁。

  5. 没有使用synchronized标记的代码段,锁机制不起作用。

  6. 无论是synchronized正常结束还是异常退出,都会释放锁。

使用格式

Synchronized标记方式有两种:

  • synchronized(obj)area ; //obj是临界资源【一个对象】,area是临界区【一段代码】。

  • synchronized方法声明

    //比如:publicsynchronized void function(){……}

    //等价于publicvoid function(){synchronized(this){area}}(第一种表达方式)


谈到线程互斥问题有个很经典的案例就是银行存钱取钱问题,来实现一下:

/**
 * 存钱取钱问题
 * 分析:
 * 账户类Account   取钱线程类Saver   存钱线程类Fetcher
 * 临界资源->账户类的实例   临界区->存取钱动作
 * @author jin
 *
 */
public class TakeSavingMoney {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Account account=new Account("晋瑜", 5000000);
		// 存入1000000
		(new Saver(account, 1000000)).start();
		// 取出30000
		(new Fetcher(account, 30000)).start();
		// 取出450000
		(new Fetcher(account, 450000)).start();
		// 存入50000
		(new Saver(account, 50000)).start();
	}

}
class Account{	// 账户类
	private String name;	// 账户名
	private double money;	// 账户余额
	
	public Account(String name, double money) {
		// TODO Auto-generated constructor stub
		this.name=name;
		this.money=money;
	}
	public String getName(){
		return this.name;
	}
	public double getMoney(){
		return this.money;
	}
	public void put(double money){	// 存钱
		this.money+=money;
	}
	public void get(double money){	// 取钱
		this.money-=money;
	}
}

class Saver extends Thread{	//存钱类
	private Account account;	// 存钱人拥有一个账户
	private double money;		// 将要存钱的数
	public Saver(Account account, double money) {
		// TODO Auto-generated constructor stub
		this.account=account;
		this.money=money;
	}
	@Override
	public void run() {
		// TODO Auto-generated method stub
		synchronized (account) {	// account是临界资源
			//临界区
			System.out.println(account.getName()+"账户\n"+"现有:"+account.getMoney()+"元\n"+"存入:"+this.money+"元.");
			account.put(this.money);
			System.out.println("现有余额:"+account.getMoney());
		}
	}
}

class Fetcher extends Thread{	//取钱类
	private Account account;	// 取款人持有一个账户
	private double money;		// 将要取钱的数
	public Fetcher(Account account, double money) {
		// TODO Auto-generated constructor stub
		this.account=account;
		this.money=money;
	}
	@Override
	public void run() {
		// TODO Auto-generated method stub
		synchronized (account) {	
			//临界区
			System.out.println(account.getName()+"账户\n"+"现有:"+account.getMoney()+"元\n"+"取出:"+this.money+"元.");
			account.get(this.money);
			System.out.println("现有余额:"+account.getMoney());
		}
	}
}
运行结果:
晋瑜账户
现有:5000000.0元
存入:1000000.0元.
现有余额:6000000.0
晋瑜账户
现有:6000000.0元
存入:50000.0元.
现有余额:6050000.0
晋瑜账户
现有:6050000.0元
取出:450000.0元.
现有余额:5600000.0
晋瑜账户
现有:5600000.0元
取出:30000.0元.
现有余额:5570000.0
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值