如何解决这个僵局?

时间:2016-03-18 11:16:06

标签: java multithreading deadlock java-threads

我在代码中添加了注释,以解释发生死锁的位置。 基本上,有两个线程。每个线程获取Manager对象上的锁,然后获取对静态资源的锁定,静态资源是应用程序中所有Manager个对象的映射。两个线程在地图上调用get()Manager类已覆盖equals()方法。 equals()进一步调用Manager类的一些同步方法。因此,地图上的get()将逐一需要对地图中的每个对象进行对象级锁定,直到关键匹配,因为等于被覆盖。 我只能更改子类(Sub1Sub2)中的代码并避免死锁,因为我无法访问其他类。

编辑:我无法访问syncMap。 “synchronized”块中的代码在我调用其API的第三方代码中执行。

我可以通过finally Manager获取锁定而不是在尝试阻止之前避免这种情况吗?!

    public class Parent{
        protected Manager manager;
    }

    public class Global{
        private static final Map syncMap = Collections.synchronizedMap(new HashMap());
        //syncMap contains all the objects of Manager in the application
    }

    class Manager{


        public boolean equals(Object o){

            Manager obj = (Manager)o;
            return obj.getURL().equals(getURL());
        }

        public final synchronized String getURL(){
            return msettings.getDBURL(); //msettings is a global variable
        }


    }


    //Thread-1 is executing someMethod() of this class

    class Sub1 extends Parent{
        Global global;
        //consider manager and Global object are not null
        public void someMethod()
        {
            synchronized(manager){// Thread-1 succesfully takes object level lock on a manager object, say Manager01
                try{
                    global.syncMap.get(manager);
                    // Thread-1 Succesfully takes class level lock on syncMap
                    //  get() calls equals() for each object in syncMap. 
                    //equals() need object lock on each Manager Object in map as it further calls synchronized getURL()
                    // But on one manager Object(Manager02) Thread-2 has already acquired lock and is waiting for lock on syncMap which this thread-1 holds

                }
                finally{
                    manager.releaseConnection();
                }

            }
        }
    }

    //Thread-2 is executing otherMethod() of this class
    class Sub2 extends Parent{ 
        public void otherMethod()
        {
            synchronized(manager){// this takes a lock on manager(Manager02)
                try{
                    global.syncMap.get(manager);
                    // this is blocked as syncMap is aquired by thread-1


                }
                finally{
                    manager.releaseConnection();
                }

            }
        } 
    }

2 个答案:

答案 0 :(得分:1)

首先,您真的应该尝试在equals方法中消除同步的需要。它会造成比它解决的更多麻烦,所以如果可以进行重新设计,那么我认为这是最好的方法。

但是,如果稍微重构代码并将global.syncMap.get(manager)移到synchronization块之前,则不会产生死锁

public Class Parent{
    protected Manager manager;
}

class Global{
    private static final Map syncMap = Collections.synchronizedMap(new HashMap());
    //syncMap contains all the objects of Manager in the application
}

class Manager{


    public boolean equals(Object o){

        Manager obj = (Manager)o;
        return obj.getURL().equals(getURL());
    }

    public final synchronized String getURL(){
        return msettings.getDBURL(); //msettings is a global variable
    }


}


//Thread-1 is executing someMethod() of this class

class Sub1 extends Parent{
    Global global;
    //consider manager and Global object are not null
    public void someMethod()
    {
         try {
             global.syncMap.get(manager);
             synchronized(manager){

             }
         }
         finally{
             manager.releaseConnection();
         }            
    }
}

//Thread-2 is executing otherMethod() of this class
class Sub2 extends Parent{ 
    public void otherMethod()
    {
         try {
             global.syncMap.get(manager);
             synchronized(manager){

             }
         }
         finally{
             manager.releaseConnection();
         }                        
    } 
}

更新 Global.class上的替代同步,可能也使用实例变量global而不是Global.class

更新已将同步更改为Manager.class而不是Global.class

class Sub1 extends Parent
{
    Global global;

    public void someMethod()
    {
        synchronized (Manager.class) { 
            try {
                global.syncMap.get(manager);
            }
            finally {
                manager.releaseConnection();
            }
        }
    }
}


class Sub2 extends Parent
{
    Global global;

    public void otherMethod()
    {
        synchronized (Manager.class) { 
            try {
                global.syncMap.get(manager);
            }
            finally {
                manager.releaseConnection();
            }
        }
    }
}

答案 1 :(得分:1)

在获得新信息之后,除了将所有处理转换为串行样式之外,我没有看到其他解决方案。因此,您可以将所有与管理器相关的API调用放在某个包装类的一个同步方法中,并将此包装器用作第三方API的单个入口点。

class BrutalWrapper {
    public synchronized void doIt(Manager manager)
    {
        try{
            global.syncMap.get(manager);

        }
        finally{
            manager.releaseConnection();
        }
    }
}

class Sub1 extends Parent{
    BrutalWrapper brutal;
    public void someMethod()
    {
        brutal.doIt(manager);
    }
}

class Sub2 extends Parent{
    BrutalWrapper brutal;
    public void someMethod()
    {
        brutal.doIt(manager);
    }
}