proposal: small utility for execute around idiom for locks

classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

proposal: small utility for execute around idiom for locks

hbrands
Administrator
Hi,

consider this code we have to write often (if you want to be thread safe):

import ca.odell.glazedlists.BasicEventList;
import ca.odell.glazedlists.EventList;

public final class AccountManager {

    final EventList<Account> accountList = new BasicEventList<>();

    public void addAccount(Account newAccount) {
        accountList.getReadWriteLock().writeLock().lock();
        try {
            accountList.add(newAccount);
            doOtherStuff();
        } finally {
            accountList.getReadWriteLock().writeLock().unlock();
        }
    }

    public boolean removeAccount(Account account) {
        accountList.getReadWriteLock().writeLock().lock();
        try {
            final boolean result = accountList.remove(account);
            doOtherStuff();
            return result;
        } finally {
            accountList.getReadWriteLock().writeLock().unlock();
        }
    }

    private void doOtherStuff() { }
    public static class Account { }
}

Especially when running on Java 8 and using lambas it would be easier/nicer to write something like:

import ca.odell.glazedlists.BasicEventList;
import ca.odell.glazedlists.EventList;
import ca.odell.glazedlists.Guarded;

public final class LambaAccountManager {
    final EventList<Account> accountList = new BasicEventList<>();

    public void addAccount(Account newAccount) {
        Guarded.byWriteLock(accountList, () -> {
            accountList.add(newAccount);
            doOtherStuff();
        });
    }

    public boolean removeAccount(Account account) throws Exception {
        return Guarded.byWriteLock(accountList, () -> {
            final boolean result = accountList.remove(account);
            doOtherStuff();
            return result;
        });
    }

    private void doOtherStuff() { }
    public static class Account { }
}

So I propose to add a small utility class which looks something like this:

import java.util.concurrent.Callable;

import ca.odell.glazedlists.util.concurrent.Lock;

public class Guarded {
    public static void byReadLock(EventList<?> list, Runnable runnable) {
        by(list.getReadWriteLock().readLock(), runnable);
    }

    public static void byWriteLock(EventList<?> list, Runnable runnable) {
        by(list.getReadWriteLock().writeLock(), runnable);
    }

    public static void by(Lock lock, Runnable runnable) {
        lock.lock();
        try {
            runnable.run();
        } finally {
            lock.unlock();
        }
    }

    public static <R> R byReadLock(EventList<?> list, Callable<R> callable) throws Exception {
        return by(list.getReadWriteLock().readLock(), callable);
    }

    public static <R> R byWriteLock(EventList<?> list, Callable<R> callable) throws Exception {
        return by(list.getReadWriteLock().writeLock(), callable);
    }

    public static <R> R by(Lock lock, Callable<R> callable) throws Exception {
        lock.lock();
        try {
            return callable.call();
        } finally {
            lock.unlock();
        }
    }
}


Do you think it's worthwhile to add something like this?

Would you place it in the core package "ca.odell.glazedlists" or in
"ca.odell.glazedlists.util.concurrent"?

How would you name this class and the methods
(do you say "guarded by a lock" or "guarded with a lock " or something else in english)?

Using a Callable as parameter type requires us to throw an exception, so it's probably better
to use another interface for returning a result?

Thanks,
Holger







Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: proposal: small utility for execute around idiom for locks

robeden
My preference would be to go whole-hog into Java 8 support and add a default method on EventList. I've seen those types of methods named "access" or "inLock".

So maybe something like:

accountList.accessRead( ()-> ... )

(or it could just be called "readLock")

If also suggest that it's time to drop the GL-specific locks and switch to Java 5's Lock.

Rob

On Sat, May 30, 2015 at 12:22 PM Holger Brands <[hidden email]> wrote:
Hi,

consider this code we have to write often (if you want to be thread safe):

import ca.odell.glazedlists.BasicEventList;
import ca.odell.glazedlists.EventList;

public final class AccountManager {

    final EventList<Account> accountList = new BasicEventList<>();

    public void addAccount(Account newAccount) {
        accountList.getReadWriteLock().writeLock().lock();
        try {
            accountList.add(newAccount);
            doOtherStuff();
        } finally {
            accountList.getReadWriteLock().writeLock().unlock();
        }
    }

    public boolean removeAccount(Account account) {
        accountList.getReadWriteLock().writeLock().lock();
        try {
            final boolean result = accountList.remove(account);
            doOtherStuff();
            return result;
        } finally {
            accountList.getReadWriteLock().writeLock().unlock();
        }
    }

    private void doOtherStuff() { }
    public static class Account { }
}

Especially when running on Java 8 and using lambas it would be easier/nicer to write something like:

import ca.odell.glazedlists.BasicEventList;
import ca.odell.glazedlists.EventList;
import ca.odell.glazedlists.Guarded;

public final class LambaAccountManager {
    final EventList<Account> accountList = new BasicEventList<>();

    public void addAccount(Account newAccount) {
        Guarded.byWriteLock(accountList, () -> {
            accountList.add(newAccount);
            doOtherStuff();
        });
    }

    public boolean removeAccount(Account account) throws Exception {
        return Guarded.byWriteLock(accountList, () -> {
            final boolean result = accountList.remove(account);
            doOtherStuff();
            return result;
        });
    }

    private void doOtherStuff() { }
    public static class Account { }
}

So I propose to add a small utility class which looks something like this:

import java.util.concurrent.Callable;

import ca.odell.glazedlists.util.concurrent.Lock;

public class Guarded {
    public static void byReadLock(EventList<?> list, Runnable runnable) {
        by(list.getReadWriteLock().readLock(), runnable);
    }

    public static void byWriteLock(EventList<?> list, Runnable runnable) {
        by(list.getReadWriteLock().writeLock(), runnable);
    }

    public static void by(Lock lock, Runnable runnable) {
        lock.lock();
        try {
            runnable.run();
        } finally {
            lock.unlock();
        }
    }

    public static <R> R byReadLock(EventList<?> list, Callable<R> callable) throws Exception {
        return by(list.getReadWriteLock().readLock(), callable);
    }

    public static <R> R byWriteLock(EventList<?> list, Callable<R> callable) throws Exception {
        return by(list.getReadWriteLock().writeLock(), callable);
    }

    public static <R> R by(Lock lock, Callable<R> callable) throws Exception {
        lock.lock();
        try {
            return callable.call();
        } finally {
            lock.unlock();
        }
    }
}


Do you think it's worthwhile to add something like this?

Would you place it in the core package "ca.odell.glazedlists" or in
"ca.odell.glazedlists.util.concurrent"?

How would you name this class and the methods
(do you say "guarded by a lock" or "guarded with a lock " or something else in english)?

Using a Callable as parameter type requires us to throw an exception, so it's probably better
to use another interface for returning a result?

Thanks,
Holger







Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: proposal: small utility for execute around idiom for locks

hbrands
Administrator
I like the idea of having that functionality on every EventList via default methods when we are on a Java 8 baseline.

However, skipping two Java versions and jumping straight ahead to Java 8 is in my opinion questionable.
Of course, we all want to get at the new stuff. But I think a lot of users (the majority?) are still on Java 7, a few on Java 6.
General purpose libraries like Guava and Apache Commons and frameworks like Spring and Hibernate are still all
Java 6 compatible AFAIK.

So being more conservative, I'd expect 1.10 on Java 6, 1.11 on Java 7 and perhaps a 2.0 on Java 8.

Dropping the GL-specific locks is a major API change which I'd defer to 2.0...

Adding the execute around utility now just to deprecate it later again when we have the default methods
does not make much sense to me.
Creating such a utility is easy enough for users themselves if they need something like that now.

I'll add an issue for adding that functionality for Java 8.
Other candidate method names would be:
accountList.readLocked(()->..)
accountList.writeLocked(()->..)
or
accountList.withReadLock(()->..)
accountList.withWriteLock(()->..)

Holger


2015-05-30 20:22 GMT+02:00 Rob Eden <[hidden email]>:
My preference would be to go whole-hog into Java 8 support and add a default method on EventList. I've seen those types of methods named "access" or "inLock".

So maybe something like:

accountList.accessRead( ()-> ... )

(or it could just be called "readLock")

If also suggest that it's time to drop the GL-specific locks and switch to Java 5's Lock.

Rob

On Sat, May 30, 2015 at 12:22 PM Holger Brands <[hidden email]> wrote:
Hi,

consider this code we have to write often (if you want to be thread safe):

import ca.odell.glazedlists.BasicEventList;
import ca.odell.glazedlists.EventList;

public final class AccountManager {

    final EventList<Account> accountList = new BasicEventList<>();

    public void addAccount(Account newAccount) {
        accountList.getReadWriteLock().writeLock().lock();
        try {
            accountList.add(newAccount);
            doOtherStuff();
        } finally {
            accountList.getReadWriteLock().writeLock().unlock();
        }
    }

    public boolean removeAccount(Account account) {
        accountList.getReadWriteLock().writeLock().lock();
        try {
            final boolean result = accountList.remove(account);
            doOtherStuff();
            return result;
        } finally {
            accountList.getReadWriteLock().writeLock().unlock();
        }
    }

    private void doOtherStuff() { }
    public static class Account { }
}

Especially when running on Java 8 and using lambas it would be easier/nicer to write something like:

import ca.odell.glazedlists.BasicEventList;
import ca.odell.glazedlists.EventList;
import ca.odell.glazedlists.Guarded;

public final class LambaAccountManager {
    final EventList<Account> accountList = new BasicEventList<>();

    public void addAccount(Account newAccount) {
        Guarded.byWriteLock(accountList, () -> {
            accountList.add(newAccount);
            doOtherStuff();
        });
    }

    public boolean removeAccount(Account account) throws Exception {
        return Guarded.byWriteLock(accountList, () -> {
            final boolean result = accountList.remove(account);
            doOtherStuff();
            return result;
        });
    }

    private void doOtherStuff() { }
    public static class Account { }
}

So I propose to add a small utility class which looks something like this:

import java.util.concurrent.Callable;

import ca.odell.glazedlists.util.concurrent.Lock;

public class Guarded {
    public static void byReadLock(EventList<?> list, Runnable runnable) {
        by(list.getReadWriteLock().readLock(), runnable);
    }

    public static void byWriteLock(EventList<?> list, Runnable runnable) {
        by(list.getReadWriteLock().writeLock(), runnable);
    }

    public static void by(Lock lock, Runnable runnable) {
        lock.lock();
        try {
            runnable.run();
        } finally {
            lock.unlock();
        }
    }

    public static <R> R byReadLock(EventList<?> list, Callable<R> callable) throws Exception {
        return by(list.getReadWriteLock().readLock(), callable);
    }

    public static <R> R byWriteLock(EventList<?> list, Callable<R> callable) throws Exception {
        return by(list.getReadWriteLock().writeLock(), callable);
    }

    public static <R> R by(Lock lock, Callable<R> callable) throws Exception {
        lock.lock();
        try {
            return callable.call();
        } finally {
            lock.unlock();
        }
    }
}


Do you think it's worthwhile to add something like this?

Would you place it in the core package "ca.odell.glazedlists" or in
"ca.odell.glazedlists.util.concurrent"?

How would you name this class and the methods
(do you say "guarded by a lock" or "guarded with a lock " or something else in english)?

Using a Callable as parameter type requires us to throw an exception, so it's probably better
to use another interface for returning a result?

Thanks,
Holger








Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: proposal: small utility for execute around idiom for locks

robeden
Java 7 has been EOL'd by Oracle. And just because there's a new version doesn't mean those on older versions have to stop using GL. We're not exactly cranking out new GL releases at this point so sticking with a supported one doesn't put them too far behind. Worst-case scenario, maintaining version branches is much easier with git than svn.

On Tue, Jun 2, 2015 at 3:41 PM Holger Brands <[hidden email]> wrote:
I like the idea of having that functionality on every EventList via default methods when we are on a Java 8 baseline.

However, skipping two Java versions and jumping straight ahead to Java 8 is in my opinion questionable.
Of course, we all want to get at the new stuff. But I think a lot of users (the majority?) are still on Java 7, a few on Java 6.
General purpose libraries like Guava and Apache Commons and frameworks like Spring and Hibernate are still all
Java 6 compatible AFAIK.

So being more conservative, I'd expect 1.10 on Java 6, 1.11 on Java 7 and perhaps a 2.0 on Java 8.

Dropping the GL-specific locks is a major API change which I'd defer to 2.0...

Adding the execute around utility now just to deprecate it later again when we have the default methods
does not make much sense to me.
Creating such a utility is easy enough for users themselves if they need something like that now.

I'll add an issue for adding that functionality for Java 8.
Other candidate method names would be:
accountList.readLocked(()->..)
accountList.writeLocked(()->..)
or
accountList.withReadLock(()->..)
accountList.withWriteLock(()->..)

Holger


2015-05-30 20:22 GMT+02:00 Rob Eden <[hidden email]>:
My preference would be to go whole-hog into Java 8 support and add a default method on EventList. I've seen those types of methods named "access" or "inLock".

So maybe something like:

accountList.accessRead( ()-> ... )

(or it could just be called "readLock")

If also suggest that it's time to drop the GL-specific locks and switch to Java 5's Lock.

Rob

On Sat, May 30, 2015 at 12:22 PM Holger Brands <[hidden email]> wrote:
Hi,

consider this code we have to write often (if you want to be thread safe):

import ca.odell.glazedlists.BasicEventList;
import ca.odell.glazedlists.EventList;

public final class AccountManager {

    final EventList<Account> accountList = new BasicEventList<>();

    public void addAccount(Account newAccount) {
        accountList.getReadWriteLock().writeLock().lock();
        try {
            accountList.add(newAccount);
            doOtherStuff();
        } finally {
            accountList.getReadWriteLock().writeLock().unlock();
        }
    }

    public boolean removeAccount(Account account) {
        accountList.getReadWriteLock().writeLock().lock();
        try {
            final boolean result = accountList.remove(account);
            doOtherStuff();
            return result;
        } finally {
            accountList.getReadWriteLock().writeLock().unlock();
        }
    }

    private void doOtherStuff() { }
    public static class Account { }
}

Especially when running on Java 8 and using lambas it would be easier/nicer to write something like:

import ca.odell.glazedlists.BasicEventList;
import ca.odell.glazedlists.EventList;
import ca.odell.glazedlists.Guarded;

public final class LambaAccountManager {
    final EventList<Account> accountList = new BasicEventList<>();

    public void addAccount(Account newAccount) {
        Guarded.byWriteLock(accountList, () -> {
            accountList.add(newAccount);
            doOtherStuff();
        });
    }

    public boolean removeAccount(Account account) throws Exception {
        return Guarded.byWriteLock(accountList, () -> {
            final boolean result = accountList.remove(account);
            doOtherStuff();
            return result;
        });
    }

    private void doOtherStuff() { }
    public static class Account { }
}

So I propose to add a small utility class which looks something like this:

import java.util.concurrent.Callable;

import ca.odell.glazedlists.util.concurrent.Lock;

public class Guarded {
    public static void byReadLock(EventList<?> list, Runnable runnable) {
        by(list.getReadWriteLock().readLock(), runnable);
    }

    public static void byWriteLock(EventList<?> list, Runnable runnable) {
        by(list.getReadWriteLock().writeLock(), runnable);
    }

    public static void by(Lock lock, Runnable runnable) {
        lock.lock();
        try {
            runnable.run();
        } finally {
            lock.unlock();
        }
    }

    public static <R> R byReadLock(EventList<?> list, Callable<R> callable) throws Exception {
        return by(list.getReadWriteLock().readLock(), callable);
    }

    public static <R> R byWriteLock(EventList<?> list, Callable<R> callable) throws Exception {
        return by(list.getReadWriteLock().writeLock(), callable);
    }

    public static <R> R by(Lock lock, Callable<R> callable) throws Exception {
        lock.lock();
        try {
            return callable.call();
        } finally {
            lock.unlock();
        }
    }
}


Do you think it's worthwhile to add something like this?

Would you place it in the core package "ca.odell.glazedlists" or in
"ca.odell.glazedlists.util.concurrent"?

How would you name this class and the methods
(do you say "guarded by a lock" or "guarded with a lock " or something else in english)?

Using a Callable as parameter type requires us to throw an exception, so it's probably better
to use another interface for returning a result?

Thanks,
Holger








Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: proposal: small utility for execute around idiom for locks

hbrands
Administrator
End of public updates for Java 7 does not imply that it's not used anymore.
Again, I think that the majority still uses Java 7, although Java 8 is catching up.
And there are folks supporting Java 7 and Java 8 runtimes for their applications for a period of time
until all customers have migrated to Java 8, so they still use Java 7 syntax (like my company ;-))
Also, startup of java webstart applications has slowed down with recent Java 8 releases, so there
are other reasons why people won't upgrade yet.

Perhaps we can agree on a compromise:
We skip Java 6 altogether and work towards a 1.10 version with Java 7 as baseline.
After that release we move the trunk to Java 8 as baseline and start publishing snapshots from there.

Any other opinions out there?

Holger


2015-06-03 15:41 GMT+02:00 Rob Eden <[hidden email]>:
Java 7 has been EOL'd by Oracle. And just because there's a new version doesn't mean those on older versions have to stop using GL. We're not exactly cranking out new GL releases at this point so sticking with a supported one doesn't put them too far behind. Worst-case scenario, maintaining version branches is much easier with git than svn.


On Tue, Jun 2, 2015 at 3:41 PM Holger Brands <[hidden email]> wrote:
I like the idea of having that functionality on every EventList via default methods when we are on a Java 8 baseline.

However, skipping two Java versions and jumping straight ahead to Java 8 is in my opinion questionable.
Of course, we all want to get at the new stuff. But I think a lot of users (the majority?) are still on Java 7, a few on Java 6.
General purpose libraries like Guava and Apache Commons and frameworks like Spring and Hibernate are still all
Java 6 compatible AFAIK.

So being more conservative, I'd expect 1.10 on Java 6, 1.11 on Java 7 and perhaps a 2.0 on Java 8.

Dropping the GL-specific locks is a major API change which I'd defer to 2.0...

Adding the execute around utility now just to deprecate it later again when we have the default methods
does not make much sense to me.
Creating such a utility is easy enough for users themselves if they need something like that now.

I'll add an issue for adding that functionality for Java 8.
Other candidate method names would be:
accountList.readLocked(()->..)
accountList.writeLocked(()->..)
or
accountList.withReadLock(()->..)
accountList.withWriteLock(()->..)

Holger


2015-05-30 20:22 GMT+02:00 Rob Eden <[hidden email]>:
My preference would be to go whole-hog into Java 8 support and add a default method on EventList. I've seen those types of methods named "access" or "inLock".

So maybe something like:

accountList.accessRead( ()-> ... )

(or it could just be called "readLock")

If also suggest that it's time to drop the GL-specific locks and switch to Java 5's Lock.

Rob

On Sat, May 30, 2015 at 12:22 PM Holger Brands <[hidden email]> wrote:
Hi,

consider this code we have to write often (if you want to be thread safe):

import ca.odell.glazedlists.BasicEventList;
import ca.odell.glazedlists.EventList;

public final class AccountManager {

    final EventList<Account> accountList = new BasicEventList<>();

    public void addAccount(Account newAccount) {
        accountList.getReadWriteLock().writeLock().lock();
        try {
            accountList.add(newAccount);
            doOtherStuff();
        } finally {
            accountList.getReadWriteLock().writeLock().unlock();
        }
    }

    public boolean removeAccount(Account account) {
        accountList.getReadWriteLock().writeLock().lock();
        try {
            final boolean result = accountList.remove(account);
            doOtherStuff();
            return result;
        } finally {
            accountList.getReadWriteLock().writeLock().unlock();
        }
    }

    private void doOtherStuff() { }
    public static class Account { }
}

Especially when running on Java 8 and using lambas it would be easier/nicer to write something like:

import ca.odell.glazedlists.BasicEventList;
import ca.odell.glazedlists.EventList;
import ca.odell.glazedlists.Guarded;

public final class LambaAccountManager {
    final EventList<Account> accountList = new BasicEventList<>();

    public void addAccount(Account newAccount) {
        Guarded.byWriteLock(accountList, () -> {
            accountList.add(newAccount);
            doOtherStuff();
        });
    }

    public boolean removeAccount(Account account) throws Exception {
        return Guarded.byWriteLock(accountList, () -> {
            final boolean result = accountList.remove(account);
            doOtherStuff();
            return result;
        });
    }

    private void doOtherStuff() { }
    public static class Account { }
}

So I propose to add a small utility class which looks something like this:

import java.util.concurrent.Callable;

import ca.odell.glazedlists.util.concurrent.Lock;

public class Guarded {
    public static void byReadLock(EventList<?> list, Runnable runnable) {
        by(list.getReadWriteLock().readLock(), runnable);
    }

    public static void byWriteLock(EventList<?> list, Runnable runnable) {
        by(list.getReadWriteLock().writeLock(), runnable);
    }

    public static void by(Lock lock, Runnable runnable) {
        lock.lock();
        try {
            runnable.run();
        } finally {
            lock.unlock();
        }
    }

    public static <R> R byReadLock(EventList<?> list, Callable<R> callable) throws Exception {
        return by(list.getReadWriteLock().readLock(), callable);
    }

    public static <R> R byWriteLock(EventList<?> list, Callable<R> callable) throws Exception {
        return by(list.getReadWriteLock().writeLock(), callable);
    }

    public static <R> R by(Lock lock, Callable<R> callable) throws Exception {
        lock.lock();
        try {
            return callable.call();
        } finally {
            lock.unlock();
        }
    }
}


Do you think it's worthwhile to add something like this?

Would you place it in the core package "ca.odell.glazedlists" or in
"ca.odell.glazedlists.util.concurrent"?

How would you name this class and the methods
(do you say "guarded by a lock" or "guarded with a lock " or something else in english)?

Using a Callable as parameter type requires us to throw an exception, so it's probably better
to use another interface for returning a result?

Thanks,
Holger









Loading...