简体   繁体   中英

Lock threads only if access same method of the same object

I have an Object with common methods of my project with multi-threading. Some methods are synchronized. My problem is when one of the threads access a sync method and another thread access another sync method. That will make one of the threads to wait for the other. I want to lock the threads only if access the same sync method, but I don't know how. I discovered recently keyword synchronized.

Here is one of my methods.

public synchronized static void writeError(Exception err){

    String time = longDate();//here will get personalized current date
                             //longDate is not synchronized.

    try {

        FileWriter  path = new FileWriter("ERROR - " + time + ".txt",true);

        err.printStackTrace(new PrintWriter(path));

        path.flush();

    } catch (IOException e) {}

}

Any idea for this method?

So synchronized always needs an object to operate on. All synchronized blocks that share the same object are mutually exclusive (ie only one thread can enter the block at a time). Putting synchronized in the method declaration is short hand, for instance methods it's equal to synchronized(this) and static methods it's synchronized(Foo.class) (where Foo is the class containing the static method).

Knowing this, you can easily create multiple objects to synch on, controlling which methods can be run at the same time and which can't.

Example class that allows method3 to be run at the same time as method1 or method2, but method1 and method2 are mutually exclusive. Additionally only one thread may run each method at a time.

public class Foo {
    private final static Object lock1 = new Object();
    private final static Object lock2 = new Object();

    public static void method1() {
        synchronized(lock1) {
            ...
        }
    }

    public static void method2() {
        synchronized(lock1) {
            ...
        }
    }

    public static void method3() {
        synchronized(lock2) {
            ...
        }
    }
}

Pay attention to static vs. non-static also. Here the methods are static and the locks are static, so all is good. If the methods were non-static, it would prevent calling the methods on different objects as well, this might not be what you want. In that case making the locks non-static would make each Foo instance work as previously described, but there wouldn't be locking in the case of foo1.method1() and foo2.method2() as they wouldn't be synchronizing on the same object.

As Shubham Kadlag's answer demonstrates, synchronized is far from the only concurrency tool Java has. The java.util.concurrent.locks package has classes for locking (whereas synchronized is a built-in mechanism). For example the ReentrantReadWriteLock allows you to handle situations where multiple threads can do something (read) at the same time, but only one thread is allowed do a modification operation (write) at a time. They also allow you to give a timeout to locking, whereas synchronized will happily wait forever (not that tryLock() is often required, since it's a programming error if you're getting deadlocks).

Then you realize that manual locking is for chumps anyway, and find that java.util.concurrent has many classes that hide the locking from you and offer all sorts of advanced functionality.

As mentioned by Kamayan, the synchronization on objects will fulfill your needs.

Moreover if you have performance issues or you have large number of threads you can go for locks.

Refer https://dzone.com/articles/synchronized-vs-lock

As pointed out in the above post, synchronized is best for a small number of threads accessing a lock (<4) and Lock may be best for a high number of threads accessing the same locks.

You can refer http://winterbe.com/posts/2015/04/30/java8-concurrency-tutorial-synchronized-locks-examples/ for different lock examples.

Create a separate lock for all methods like below.

private static ReentrantLock writeErrorlock = new ReentrantLock();

        public static void writeError(Exception err){
            writeErrorlock.lock();
            String time = longDate();//here will get personalized current date
                                     //longDate is not synchronized.

            try {

                FileWriter  path = new FileWriter("ERROR - " + time + ".txt",true);

                err.printStackTrace(new PrintWriter(path));

                path.flush();

            } catch (IOException e) {

            }
            finally {
                writeErrorlock.unlock();
            }

        }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM