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();
}
}