如何在Java中正确同步方法访问

时间:2015-11-08 02:26:39

标签: java multithreading synchronized

我有一个类Library,它是第三方库,我无法访问源代码。这个类用在我的项目的不同类中,例如

public class MyOwnClass1 {
    private Library lib;
    public void doTask () {
        String res = lib.libMethod1();
        ... ... ...
    }
}

然而,事实证明类Library不是线程安全的,例如,当在不同的线程中同时调用方法libMethod1时,它会导致奇怪问题。

因此,我必须实现自己的线程安全机制,第一个是将Library变量封装到另一个类中。

public class SafeLibrary {
    private Library lib;
    private Object mutex = new Object();
    ... ... ...
    public String doTask () {
        synchronized(this.mutex) {
            return this.lib.libMethod1();
        }
    }
    ... ... ...
}

但正如我所说,Library类用于不同类的不同方法。如果我必须将所有相关方法放入新的SafeLibrary类中,则会花费大量代码修改。

所以这是第二个想法:

public class SafeLibrary {
    private Library lib;
    private Object mutex = new Object();
    public Object getMutex() {
        return this.mutex;
    }
    public Library getLib() {
        return this.lib;
    }
}

然后我在我自己的类中同步方法访问:

public class MyOwnClass1 {
    private SafeLibrary lib;
    public void doTask () {
        synchronized(lib.getMutext()) {
            String res = lib.getLib().libMethod1();
            ... ... ...
        }
    }
}

通过使用第二种解决方案,我只需要对相关方法进行一些小的修改。但是getMutex()似乎是不合适的方式。

我想知道哪种解决方案是正确的,或者是否还有其他更好的解决方案?感谢。

2 个答案:

答案 0 :(得分:1)

您有两个选项,可以同步您的类或同步特定方法。你做的是同步一个类。以下是同步类的示例: https://docs.oracle.com/javase/tutorial/essential/concurrency/syncrgb.html

以下是同步方法的示例: https://docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html

基本上只需在“public”之后和返回值之前添加“synchronized”一词。可以把它想象成为方法添加“final”。

最佳解决方案取决于您的软件架构。如果只是您担心的一种方法,并且该方法是您正在创建的对象的特征,那么只需同步该方法即可。如果要创建其他对象/线程需要的独立对象,则同步该对象。

答案 1 :(得分:1)

如果您想要使用的库和方法不是最终的,并且您自己创建库对象(而不是从库本身的静态方法获取它),那么您可以创建自己的类:

public class SynchronizedLibrary extends Library {
    public synchronized String libMethod1() {
        super.libMethod1();
    }
}

然后你所要做的就是替换构造函数调用,甚至可以将声明的类型保留为普通的旧库(尽管你可能不想这样做)。