vesontio
vesontio

Reputation: 381

How to correctly synchronize method access in Java

I have a class Library which is a third-part library that I don't have access to the source code. This class is used in different class of my project, such as

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

However, it turns out that the class Library is not thread-safe, for instance, when the method libMethod1 is called simultaneously in different threads, it causes weird problems.

Thus, I have to implement my own thread-safe mechanisms, the 1st one is to encapsulate the Library variable into an other class.

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

But as I said, the Library class is used in different methods of different class. If I have to place all the related method into the new SafeLibrary class, it will cost a lot of code modification.

So Here is the 2nd idea:

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

Then I synchronize the method access in my own class:

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

By using the 2nd solution, I only have to do some small modifications in related methods. But the getMutex() seems an improper way to go.

I'd like to know which solution is correct, or if there is a an other better solution ? Thanks.

Upvotes: 0

Views: 92

Answers (2)

ILMTitan
ILMTitan

Reputation: 11017

If Library and the methods you want to use are not final, and you create the library object yourself (rather than getting it from a static method of Library itself), then you can create your own class:

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

Then all you have to do is replace the constructor calls, and can even leave the declared type as plain old Library (although you may not want to).

Upvotes: 1

Gene
Gene

Reputation: 11267

You have two options, you can either synchronize your class or synchronize a particular methods. What you did with was synchronize a class. Here's an example on synchronizing a class: https://docs.oracle.com/javase/tutorial/essential/concurrency/syncrgb.html

Here's an example of synchronizing a method: https://docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html

Basically just add the word "synchronized" after the "public" and before the return value. Think of it like adding "final" to a method.

The best solution will depend on your software architecture. If it's just that one method you are worried about and that method is a characteristic of the object you are creating, then just synchronize the method. If you're creating an independent object that other objects/threads need, then synchronize the object.

Upvotes: 1

Related Questions