并发—实现自己的同步锁

Java同步锁

Synchronized 关键字原理参考JavaGuide/Java相关/synchronized.md

实现自己的同步锁

实现锁

根据 Synchronized 的原理,可以实现自己的同步锁如下:

/**
 * 模拟锁的实现原理(synchronized)
 * @author ljx
 * @Date Jan 14, 2019 9:21:10 PM
 */
public class Lock {
	/**
	 * 存在于每个对象头中,所以Java中可以使用任何对象作为锁
	 * 原理:
	 * 	线程试图获取锁,也就是试图获取 minitor 的持有权,当计数器的值为 0 时,获取锁成功,
	 * 	获取锁后,将计数器的值加 1 。(在可重入锁中,可以对计数器再执行加的操作)。
	 *  释放锁:将计数器的值减 1 。(在可重如锁中,直到计数器的值为 0 才算释放成功)。
	 */
	static class Monitor{
		public int value = 0;
		public String owner;
		public Monitor() {}
		public Monitor(String o) {
			this.owner = o;
		}
	}
	
	public Monitor monitor = new Monitor();
	
	/**
	 * 获取锁,获取不到返回false
	 * @param o
	 * @return
	 */
	public boolean lock(String o) {
		if(monitor.value != 0) {
			return false;
		}else {
			monitor.owner = o;
			monitor.value++;
			return true;
		}
	}
	
	/**
	 * 获取锁,一定能获取,暂时获取不到就等待,类似自旋锁
	 * FIXME: 设置自旋时间,超时停止
	 * @param owner
	 */
	public void lock1(String owner) {
		if(monitor.value != 0) {
			while(monitor.value != 0) {
				// 轮询,每 300 ms 查看一下状态
				try {
					Thread.sleep(300);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
		monitor.owner = owner;
		monitor.value++;
	}
	
	public void unlock() {
		monitor.owner = "";
		monitor.value--;
	}
}

使用锁

使用存取钱的例子来使用锁。
账户类:账户实现同步控制,对存取线程透明

import java.math.BigDecimal;

/**
 * 基于锁实现存取钱操作
 * @author ljx
 * @Date Jan 15, 2019 10:45:30 AM
 */
public class Account {

	volatile BigDecimal amount ;
	private Lock lock = new Lock();
	private String name ;
	public Account(String name,BigDecimal amount) {
		this.name = name;
		this.amount = amount;
	}
	
	public boolean deposit(String i) {
		lock.lock1(name);
		try {
			try {
				Thread.sleep(2000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			amount = amount.add(new BigDecimal(i));
		}finally {
			lock.unlock();
		}
		return true;
	}
	
	public BigDecimal withdraw(String i) {
		lock.lock1(name);
		BigDecimal ret = new BigDecimal(i);
		try {
			try {
				Thread.sleep(3000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			if(new BigDecimal(i).compareTo(this.amount) > 0) {
				System.out.println("withdraw fail ,amount not enough");
				return new BigDecimal("-1");
			}else {
				amount = amount.subtract(ret);
				return ret;
			}
		}finally {
			lock.unlock();
		}
		
	}
}

存钱线程

/**
 * @author ljx
 * @Date Jan 15, 2019 11:22:29 AM
 */
public class Deposit extends Thread{
	private Account account;
	private String val;
	
	public Deposit(Account a,String val) {
		this.account = a;
		this.val = val;
	}
	
	@Override
	public void run() {
		boolean v = this.account.deposit(this.val);
		System.out.println("deposit money "+v+" ,amount:"+account.amount);
	}
}

取钱线程

import java.math.BigDecimal;

/**
 * @author ljx
 * @Date Jan 15, 2019 11:27:56 AM
 */
public class Withdraw extends Thread{

	private Account account;
	private String val;
	
	public Withdraw(Account a,String val) {
		this.account = a;
		this.val = val;
	}
	
	@Override
	public void run() {
		BigDecimal money = this.account.withdraw(this.val);
		if(money.compareTo(new BigDecimal("-1")) != 0) {
			System.out.println("withdraw money:"+money+" ,amount:"+account.amount);
		}
	}
}

运行

import java.math.BigDecimal;

/**
 * @author ljx
 * @Date Jan 15, 2019 11:32:05 AM
 */
public class DepositWithdraw {
	
	public static void main(String[] asc) {
		Account a = new Account("a",new BigDecimal("40")); // 原本 40
		Deposit deposit = new Deposit(a,"10");// 存 10 的任务
		Withdraw withdraw = new Withdraw(a,"50");// 取 30 的任务
		
		System.out.println("account amount:"+a.amount);
		// 可以切换存取的顺序观察结果
		withdraw.start(); // 先取
		deposit.start();
	}
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值