This example is the same as used in the shared container topic. Except that it is using read and write locks.
We replace the lock object with a read write lock:
private final ReadWriteLock dataLock = new ReentrantReadWriteLock();
And then on reading operations you use the read lock:
private void listAllPeople(ObjectContainer container) { dataLock.readLock().lock(); try{ for (Person person : container.query(Person.class)) { System.out.println(person.getName()); } } finally{ dataLock.readLock().unlock(); } }
On insert and update operations you grab the write lock. Note that you need the write lock every time you change some data.
private void updateSomePeople(ObjectContainer container) { dataLock.writeLock().lock(); try { final ObjectSet<Person> people = container.query(new Predicate<Person>() { @Override public boolean match(Person person) { return person.getName().equals("Joe"); } }); for (Person joe : people) { joe.setName("New Joe"); container.store(joe); } } finally { dataLock.writeLock().unlock(); } }
You can use read write locks also in a transaction abstraction. This example is an extension of transaction abstraction example but with read write locks.
First we introduce the read write lock.
private final ReadWriteLock dataLock = new ReentrantReadWriteLock();
Then we implement read and write transaction methods:
public <T> T inReadTransaction(TransactionFunction<T> transactionClosure) { return inTransaction(dataLock.readLock(),transactionClosure); }
public <T> T inWriteTransaction(TransactionFunction<T> transactionClosure) { return inTransaction(dataLock.writeLock(),transactionClosure); }
private <T> T inTransaction(Lock lockToGrab,TransactionFunction<T> transactionClosure) { lockToGrab.lock(); try { return transactionClosure.inTransaction(database); } catch (Exception e) { database.rollback(); throw new TransactionFailedException(e.getMessage(), e); } finally { database.commit(); lockToGrab.unlock(); } }
After that we can use these operations in our code:
private void listAllPeople(DatabaseSupportWithReadWriteLock dbSupport) { dbSupport.inReadTransaction(new TransactionAction() { @Override public void inTransaction(ObjectContainer container) { final ObjectSet<Person> result = container.query(Person.class); for (Person person : result) { System.out.println(person.getName()); } } }); }
private void updateAllJoes(DatabaseSupportWithReadWriteLock dbSupport) { dbSupport.inWriteTransaction(new TransactionAction() { @Override public void inTransaction(ObjectContainer container) { final ObjectSet<Person> allJoes = container.query(new Predicate<Person>() { @Override public boolean match(Person person) { return person.getName().equals("Joe"); } }); for (Person joe : allJoes) { joe.setName("New Joe"); container.store(joe); } } }); }