How to sync inside default interface 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 that I want to synchronize with 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 } } 

Decision? Smart workarounds? Or just live with him :)!

+6
source share
3 answers

You can put the lock object in the pubic static field of the visible package class, allowing all of your methods to share the lock by default. The lock remains visible inside your library, but since classes with default access are not visible outside your library, the lock will be closed to users of your interface outside of 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 for your library as a whole, this trick gives you the same advantages as using a private lock object compared to synchronizing with this , since it prevents access to your blocking malicious code written by outsiders. Of course, any lock can be hijacked part of your library.

+2
source

You can add the getLock () method to your interface and each of them will return an object for locking.

+1
source

To understand that it might be possible ...

I put the lock object in the static field of the visible package class, allowing all my methods to share the lock by default. The lock provider provides instances of its own locks on demand. The lock is removed from the collection when the instance collects garbage.

The lock provider creates the lock on the first request from the instance and then returns the same lock. It looks like this:

 final class LockProvider { private static final WeakHashMap<Widget,Object> widgetLocks = new WeakHashMap<>(); static Object obtainLock(Widget w) { synchronized (widgetLocks) { return locks.computeIfAbsent(w, x -> new Object()); } } } 

And now the default interface method is as follows:

 public interface Widget{ default void addSomething(List<String> names) { synchronized (LockProvider.obtainLock(this)) { ... do something } } } 

One weakness is that WeakHashMap uses Object.hashcode() and Object.equals() . Another thing is that, although fast, it is not super-high-performance. Although this doiung method seems smart ... any method that requires synchronization on a closed lock will be better developed in a different way.

[UPDATED]

In the end, I did the following:

1) create default methods:

 public interface Widget{ default void addSomething(List<String> something) { ... do something } } 

2) Then both regular and thread safe implementations were created

 public class WidgetImpl implements Widget{ ... } // Threadsafe version public class WidgetThreadsafeImpl implements Widget{ private final Object lock = new Object(); public void addSomething(List<String> something) { synchronized(lock){ super.addSomething(something); } } } 

The default method provides an algorithm, and implementations can provide thread-safe or non-thread-safe implementations.

0
source

Source: https://habr.com/ru/post/959116/


All Articles