日期:2014-05-20  浏览次数:20758 次

java中互斥锁的问题: 当几个参数对象的所有属性值相同时就上互斥锁
这个问题其实我在百度上面已经问过,但是没人回应,所以.. 
还请大家帮帮忙哈 
言归正传,问题:
例如:

public void doSomething(Person person){
    synchronized(person){
        system.out.println("start: "+person.getId());
        Thread.sleep(5000);
        system.out.println("end: "+person.getId());
    }
}

我做的是web开发,当我开两个浏览器对同一个对象进行 doSomething 操作时,发现它们不会互斥
我想大概是这两个值相同的对象不是同一对象的原因吧, 求大神帮忙想想办法,如何才能让两个person对象的所有属性值相同的时候就互斥. 谢谢!

谢谢! 我刚刚测了一下,找到了答案,可以利用String对象的特殊性来进行上锁,
因为对象的id是唯一的,所以可以用对象的id来作为锁对象. String  :对于所有的拥有相同值的String对象,只会创建一个String对象.
代码如下:

public void doSomething(Person person){
    String id=person.getId();
    synchronized(id){
       ...
    }
}

这样对于拥有相同属性的和属性值的不同的person对象来说,就可以进行互斥啦!
//但是 我如果不在synchronized块上面定义 id 对象,而直接调用getId方法来作为锁对象就不能互斥了:  这是为什么了?

    //String id=person.getId();
    synchronized(person.getId()){
        ....
    }

--上面写的是在一个测试类里面的,但是刚刚在项目中试了一下,居然用String也不可以... (这个方法是写在Service里面的),这是测试类和在web中的环境不同造成的吗?
------解决方案--------------------
person.getId()只是取到的值是一样的 引用又不是同一个  因为每次访问都是new 一个Person
要同步需要用外部变量做同步 你可以用一个静态成员变量
------解决方案--------------------
我不知道你的Person对象中的ID属性是怎么赋值的,你如果定义了一个String id的话JVM会进行缓存,所以...

String s1 = "abc";
String s2 = "abc";

这样两句,对JVM来说都是同一个对象.
------解决方案--------------------
ConditionalLock.java

import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class ConditionalLock {

    private final static Map<Thread, Person> relations = new ConcurrentHashMap<Thread, Person>();
    private final static ReentrantLock lock = new ReentrantLock(false);
    private final static Condition condition = lock.newCondition();

    private Person person;

    public ConditionalLock(Person p) {
        this.person = p;
    }

    public void await() {
        lock.lock();
        try {
            while (isAlreayLocked()) {
                condition.await();
            }

            relations.put(Thread.currentThread(), person);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }

    }

    public void singal() {
        lock.lock();
        try {
            condition.signal();

            relations.remove(Thread.currentThread());
        } finally {
            lock.unlock();

        }
    }

    private boolean isAlreayLocked() {
        Set<Entry<Thread, Person>> sets = relations.entrySet();
        for (Entry<Thread, Person> entry : sets) {
            Person other = entry.getValue();
            if (other == null) {
                continue;
            }
            if (this.person.equals(other)) {
                return true;