Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to synchronize inside an interface default method without using this?

I have a number of default methods in interfaces that need synchronization and it seems that only this is available:

default void addUniqueColumns(List<String> names) {
    synchronized (this) {
        ... do something
    }
}

The problem is, I want to synchronize on a private lock instead of this for better control:

default void addUniqueColumns(List<String> names) {
    synchronized (lock) {  // how to get a private lock in a default method??
        ... do something
    }
}

Solutions? Clever workarounds? Or just live with it :) !

like image 567
The Coordinator Avatar asked Dec 01 '13 11:12

The Coordinator


2 Answers

You can put the lock object into a pubic static field of a package-visible class, letting all your default methods share the lock. The lock remains visible inside your library, but since classes with default access are not visible outside your library, the lock would be private to the users of your interface outside your library:

class LockHolder { // Package private class
    public static Object LOCK = new Object();
}

public interface ColumnCollection {
    default void addUniqueColumns(List<String> names) {
        synchronized (LockHolder.LOCK) {
            ... do something
        }
    }
}

As far as your library is concerned as a whole, this trick gives you the same advantages as using a private lock object does compared to synchronizing on this, because it prevents malicious code written by outsiders from accessing your lock. Of course the lock can be grabbed by any part of your library.

like image 180
Sergey Kalinichenko Avatar answered Oct 25 '22 16:10

Sergey Kalinichenko


You could add a getLock() method to your interface and have each implementor return the object to lock over.

like image 43
ksasq Avatar answered Oct 25 '22 16:10

ksasq