java同步锁的一个偿试

前2天项目中的一个web应用,在做了几个操作后就死机,白板了,只能重启,找了半天没有错误日志,跟踪了一下业务操作,发现是前台页面的提交与后台的其他应用并发引起死锁操作,几人把该同志的代码评审了一下,讨论了一下同步的写法,发现其锁的实现是有漏洞的。在此也总结一下,可能对其他人有所帮助,当然,感觉这种实现应该是很早就该如此的。

 

业务场景是这样的:前台应用A,后台应用B,都需要同时对资源类C进行get和set操作,但前提是每个应用在get资源后一直到其set或不set退出之前,保持C资源为其应用独占,因为C资源的操作必须是看到什么才能做什么。

例:C资源数必须>=0,A 先get C 得到100的量,经过一些判断处理决定允许将C进行减50的操作,同时B也想对C进行减80的操作,这样一来,执行的正确顺序是

1)A get c=100

2)A 判断 是否允许-50

3)A set c=100-50

4)B get c=50

5)B 判断 是否允许-80

6)B 条件不允许 退出

测试的类代码如下:

 

public class ClassA extends Thread {
	private String threadName = "";//线程名称
	private int sleepTime = 10000 ;//线程sleep时间
	private Object lock = new Object(); //锁
	private int subValue = 0 ; //被减数
	
	public ClassA(String name,int sleep,int subValue){
		this.threadName = name ;
		this.sleepTime = sleep ;
		this.subValue = subValue ;
	}
	
	public void run(){
		System.out.println(threadName + " is running ");
		synchronized (lock){
			System.out.println(threadName + " get self lock ");
			synchronized (ClassC.getLock()){
				int value = ClassC.getValue();
				System.out.println(threadName + " get C.value = "+value );
				try{
					//线程sleep 模拟应用的其他处理
					System.out.println(threadName + " now is sleeping ");
					Thread.sleep(sleepTime);
				}catch(InterruptedException e){
					e.printStackTrace();
				}
				if(value >= this.subValue){
					int newValue = value - this.subValue ;
					ClassC.setValue(newValue);
					System.out.println(threadName + " set new value = " + newValue);
				}else{
					System.out.println(threadName + " can't set new value,now is = "+ value) ;
				}
			}
		}
	}
	
	public static void main(String[] args) throws Exception {
		ClassA a = new ClassA("appA",6000,50);
		a.start();
		ClassA b = new ClassA("appB",2000,80);
		b.start();
	}
}

class ClassC {
	private static int value = 100 ;
	private static Object lock = new Object();
	public static Object getLock(){
		return lock ;
	}
	public static int getValue(){
		return value ;
	}
	public static void setValue(int newValue){
		value = newValue ;
	}
}

 当前代码执行后结果如下:

appA is running
appB is running
appB get self lock
appA get self lock
appA get C.value = 100
appA now is sleeping
appA set new value = 50
appB get C.value = 50
appB now is sleeping
appB can't set new value,now is = 50

 

我们发现的错误是在ClassA的lock使用上,当时的开发人员写的代码是下面这行:

	private String lock = ""; //锁

ClassA的锁和ClassC的锁用的都是字串,而不是Object,执行的结果就变成了:

appA is running
appB is running
appB get self lock
appB get C.value = 100
appB now is sleeping
appB set new value = 20
appA get self lock
appA get C.value = 20
appA now is sleeping
appA can't set new value,now is = 20
结果appB先把100减去80变成20,appA则不能用了

 

在试验时,大家对这一结果颇感不解,后经一人提醒,相同值的String 对象jvm会进行优化,使用相同的内存地址,以下这句话可以打印true

String a="123";
String b="123";
System.out.println( a == b);

 

所以,自我总结,应该在java中使用同步操作时,选取的对象最好是一个唯一的对象,以防止大家使用相同的对象,而使并发锁在同一个对象上,造成死锁。

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值