`
gj_gp
  • 浏览: 5926 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

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中使用同步操作时,选取的对象最好是一个唯一的对象,以防止大家使用相同的对象,而使并发锁在同一个对象上,造成死锁。

 

 

 

分享到:
评论
1 楼 plant12345 2011-03-04  
恩,直接字符串的话在 jvm 堆里面的 String 对象是同一个,如果他写成new String(""),我想也是没有问题的。

相关推荐

    支持10000同步锁,Spring Boot,Java

    文件名`java_demo_synchronized`可能包含的是关于Java同步锁的示例代码,可以从中学习如何在实际项目中应用同步锁策略。通过深入理解同步锁的工作原理和优化技巧,我们可以构建出高效、高并发的Spring Boot应用程序...

    Java 同步锁 wait notify 学习心得

    ### Java同步锁原理 在Java中,`synchronized`关键字用于实现线程同步,即确保同一时刻只有一个线程可以访问特定的代码块或方法。这种机制通过内部维护一个锁来实现,每个对象都有一个内置锁,这个锁可以被任何拥有...

    Java 同步锁(synchronized)详解及实例

    Java中的同步锁,即`synchronized`关键字,是Java多线程编程中用于解决并发问题的重要机制。它确保了对共享资源的互斥访问,防止数据的不一致性。当我们有多线程环境并涉及到共享数据时,可能会出现竞态条件,就像...

    spring实现集群同步锁

    为了解决这个问题,我们需要一种机制,即集群同步锁,来确保同一时间只有一个节点可以执行特定的操作。Spring为此提供了一种灵活的解决方案,它允许开发者选择不同的实现策略,如基于数据库的锁、基于缓存的锁(例如...

    java同步(一个网页)

    ReentrantLock是Lock的一个实现,它支持可中断的等待、公平锁以及尝试获取锁等功能。 ```java Lock lock = new ReentrantLock(); lock.lock(); try { // 临界区 } finally { lock.unlock(); } ``` 4. **...

    redis同步锁AOP实现

    当多个服务实例同时尝试访问同一资源时,Redisson的锁可以确保同一时间只有一个实例能够获取锁并执行操作,从而避免并发问题。 在Spring框架中,AOP(Aspect Oriented Programming)用于分离关注点,比如日志、事务...

    Java同步机制浅谈

    如果多个线程尝试同时访问,则只有其中一个线程能够获得执行权,其他线程将等待该方法释放锁。 2. **同步代码块**:当`synchronized`关键字用于代码块时,需要指定一个对象作为锁。只有拥有该锁的线程才能执行同步...

    解析Java线程同步锁的选择方法

    示例中推荐的同步锁对象`lock`是一个`byte[0]`数组。每个`SyncTest`实例都有自己的`lock`,因此不同实例的线程可以同时调用`method`,实现了预期的线程thread1和thread2同步,thread3和thread4同步的效果。这种做法...

    彻底理解Java中的各种锁.pdf

    轻量级锁尝试通过CAS操作减少锁的粒度。当发生锁竞争时,锁会升级为重量级锁,此时会使用操作系统的互斥量(mutex)来控制线程对共享资源的访问。 6. 锁的其他特性 除了以上所述的锁类型外,Java还提供了一些与锁...

    java锁的释放与建立

    当一个线程进入一个由`synchronized`修饰的方法或代码块时,会自动获取锁,退出时则自动释放。显式锁则是通过`java.util.concurrent.locks.Lock`接口及其实现类如`ReentrantLock`来实现,提供更细粒度的控制。 锁的...

    深入学习Java同步机制中的底层实现

    Java同步机制是多线程编程中确保数据一致性与正确性的关键。在Java中,主要有两种同步机制:内置的`synchronized`关键字以及基于`java.util.concurrent`包中的高级同步工具类。本文将深入探讨这些机制的底层实现,...

    数据访问同步锁

    同步锁的工作原理基于监视器(Monitor)概念,每个对象都有一个与之关联的监视器锁。当线程试图进入同步代码块时,会尝试获取锁,如果成功,线程获得执行权;如果失败,则会被阻塞,直到锁被释放。 除了`...

    java synchronize 线程同步

    如果多个线程尝试同时调用同一个对象的同步方法,那么只有一个线程能够获取到对象的锁并执行方法,其他线程则需要等待锁的释放。 在例子中,`execute()`方法没有被`synchronized`修饰时,两个线程并发调用同一个...

    java同步之如何写一个锁Lock

    "Java 同步锁实现原理详解" 在 Java 中,锁是实现同步的基础。 Lock 是 Java 中的一种同步机制,用于控制多个线程对共享资源的访问。在本篇文章中,我们将手动实现一个锁,探讨其实现原理,并了解 AQS 及各种同步器...

    Java锁机制详解.pdf

    显示锁的一个重要接口是Lock,它提供了对锁操作的更细粒度控制,而ReentrantLock是Lock的一个具体实现,它提供了可重入的特性,允许线程多次进入锁定的代码块。 Lock接口主要定义了以下方法: 1. lock():获取锁,...

    Java的锁机制的学习和使用

    `synchronized`默认是非公平锁,这意味着在释放锁之后,下一个获取锁的线程并不一定是等待时间最长的那个。不过,`ReentrantLock`类支持设置公平锁,这使得锁的分配更加公平。 #### 五、锁的应用场景 - **银行账户...

    Java concurrency之锁_动力节点Java学院整理

    同步锁的实现基于 monitors,每个对象都有一个与之关联的monitor,当一个线程进入synchronized代码块或方法时,会尝试获取对象的锁,如果成功,其他线程将无法同时获得该锁,必须等待锁释放后才能再次尝试获取。...

    Java线程的同步与死锁

    本文将深入探讨Java线程中的同步机制及其可能导致的一个严重问题——死锁,并通过具体的示例来帮助读者更好地理解和解决这些问题。 #### 二、Java线程同步 ##### 2.1 同步的重要性 在多线程环境中,多个线程可能会...

    java锁机制详解.pdf

    当线程尝试进入一个`synchronized`方法时,它首先检查是否已经有人持有该锁。如果没有,它就获取锁并执行方法;如果有,它就会被阻塞,直到锁被释放。对于`synchronized`代码块,可以指定锁定的对象,这样就允许更...

Global site tag (gtag.js) - Google Analytics