I need a threadsafe arraylist like this.
public class BookingList {
private List<Booking> bookings;
public BookingList() {
bookings = Collections.synchronizedList(new ArrayList<Booking>());
}
#Override
public void addBooking(Booking booking)
{
synchronized (bookings) {
bookings.add(booking);
}
}
#Override
public void removeBooking(Booking booking)
{
synchronized (bookings) {
bookings.remove(booking);
}
}
}
According to java doc, when using Collections.synchronizedList one needs to synchronize each access to the list. I'm not sure whether my synchronized blocks will do this?
Is my use of synchronized blocks equivalent to
...
public synchronized void addBooking(Booking booking) {
bookings.add(booking);
}
Should I use a ReentrantLock like this
private Lock lock = new ReentrantLock();
public void addBooking(Booking booking) {
try {
lock.lock;
bookings.add(booking);
} finally {
lock.release();
}
}
You don't need to synchronize simple operations like add or remove because this is handled internally by the implementation and this is precisely why you use them: to avoid handling the synchronization yourself
But for composite operations like iterations or multiple removal that are out of the scope of the internal synchronization you must provide your own locking mechanism.
To answer your questions:
1:
public synchronized void addBooking(Booking booking) {
bookings.add(booking);
}
is equivalent to
public void addBooking(Booking booking) {
synchronized (this){
bookings.add(booking);
}
}
2: for your example you should not use ReentrantLock. Calling methods of a list that has been initialized with Collections.synchronizedList() is thread-safe, no further synchronized or other locking mechanisms have to be used. For the rest see #Pragmateek's answer.
Related
I have two synchronized methods, each of them is being executed by a different Thread.
public synchronized ResultSet dbExecuteQuery(String queryStmt);
public synchronized void dbExecuteUpdate(String queryStmt);
How can I make sure their execution won't "overlap"?
One solution that comes to my mind is the following:
public synchronized ResultSet dbExecute(String queryStmt, boolean isUpdate) {
if (isUpdate) {
dbExecuteUpdate(queryStmt);
return null;
} else
return dbExecuteQuery(queryStmt);
}
But it means I would have to change all code used in the whole project. Is there a cleaner way to do it?
You can add a dedicated synchronization object:
class YourClass {
Object syncObject = new Object();
public ResultSet dbExecuteQuery(String queryStmt) {
synchronized(syncObject) {
// your code
}
}
public void dbExecuteUpdate(String queryStmt) {
synchronized(syncObject) {
// other code
}
}
}
But it's probably better to use a ReentrantLock.
class YourClass {
private Lock lock = new ReentrantLock();
public ResultSet dbExecuteQuery(String queryStmt) {
lock.lock();
// your code
lock.unlock();
}
public void dbExecuteUpdate(String queryStmt) {
lock.lock();
// other code
lock.unlock();
}
}
Actually, since one is a read and one a write, you probably want to use ReadWriteLock.
class YourClass {
private ReadWriteLock lock = new ReentrantReadWriteLock();
public ResultSet dbExecuteQuery(String queryStmt) {
lock.readLock().lock();
// your code
lock.readLock()..unlock();
}
public void dbExecuteUpdate(String queryStmt) {
lock.writeLock()..lock();
// other code
lock.writeLock().unlock();
}
}
This way you can have several threads reading concurrently:
The read lock may be held simultaneously by multiple reader threads, so long as there are no writers. The write lock is exclusive.
Consider the following code implementing double check locking using the synchronized keyword in JAVA 8:
private static void redoHeavyInitialisation() {
if (needToReinitialise()) {
synchronized (MyClass.class) {
if (needToReinitialise()) {
doHeavyInitialisation();
}
}
}
}
The reason double check locking is used is because the initialisation is heavy (hence lazy) AND it can happen more than once (hence singleton pattern can not be used, correct me if I am wrong).
Anyway, first, how do you convert the code above to use Lock from the JAVA concurrent package instead of using synchronized keyword?
Only after that AND optionally, feel free to comment on using Lock or synchronized keyword which one is better.
Remember, this question is not about Lock vs synchronized comparison. Answer attempts without answering the code conversion part will not be picked as accepted answer.
Transformation of synchronized blocks to the equivalent block using ReentrantLock is pretty rote.
First you create a lock with the same or similar scope and lifetime as the object you were locking on. Here you are locking on MyClass.class, hence a static lock, so you can map this to a static lock in MyClass, such as MyClass.initLock.
Then just replace each:
synchronized (object) {
with
lock.lock();
try {
and each associated closing brace with
} finally {
lock.unlock();
}
Putting it all together you have:
private final static ReentrantLock initLock = new ReentrantLock();
private static void redoHeavyInitialisation() {
if (needToReinitialise()) {
MyClass.initLock.lock();
try {
if (needToReinitialise()) {
doHeavyInitialisation();
}
} finally {
MyClass.initLock.unlock();
}
}
}
Performance-wise there is little daylight between the approaches. They essentially have the same semantics and usually use similar underlying mechanisms. In the past, there have been performance differences - sometimes optimizations have gone in that affect one or the other, so on some JVMs you can find a difference, but the whole point of double checked locking is to avoid taking the lock anyway, so just do what's simplest. You only get the lock for a very small transitory period while the needToReinitialise() method is running, so the locking cost won't have any ongoing impact.
Consider the following code:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class HeavyInitializer {
static final Logger logger = LoggerFactory.getLogger(HeavyInitializer.class);
static HeavyInitializer singleton;
public static synchronized HeavyInitializer getInstance() {
if (singleton==null) {
singleton = new HeavyInitializer();
}
return singleton;
}
boolean initialized;
private HeavyInitializer() {
initialized = false;
}
public synchronized void initialize() {
if (!initialized) {
heavyStuffDoneHere();
}
}
public synchronized void reInitilize() {
if (needToReinitialise()) {
heavyStuffDoneHere();
}
}
private void heavyStuffDoneHere() {
initialized = true;
}
private boolean needToReinitialise() {
if (!initialized)
return false;
boolean ret = false;
//Do your check here... and set ret
return ret;
}
}
From Oracle's doc:
... then making these methods synchronized has two effects:
First, it is not possible for two invocations of synchronized methods on the same object to interleave. When one thread is executing a synchronized method for an object, all other threads that invoke synchronized methods for the same object block (suspend execution) until the first thread is done with the object.
Second, when a synchronized method exits, it automatically establishes a happens-before relationship with any subsequent invocation of a synchronized method for the same object. This guarantees that changes to the state of the object are visible to all threads.
Trying to use Lock would be trying to reimplement the synchronized block. Not necessary.
Singleton Double checks the lock and prevents singleton object to break using serialization.
package pattern.core.java;
import java.io.Serializable;
public class Singleton extends Object implements Serializable {
private static final long serialVersionUID = 1L;
private static Singleton sg;
private Singleton() {
}
public static Singleton getSingletonObj() {
if (sg == null) {
synchronized (sg) {
if (sg == null) {
sg = new Singleton();
}
}
}
return sg;
}
/*
* this method ensures that new object will not be created for singleton
* class using serialization and deserialization
*/
protected Object readResolve() {
return sg;
}
/*
* #Override protected Object clone() throws CloneNotSupportedException {
* throw new CloneNotSupportedException(); }
*/
#Override
protected Object clone() throws CloneNotSupportedException {
return sg;
}
}
I have wrote following wrapepr:
public class AutoCloseableLockWrapper implements AutoCloseable, Lock{
private final Lock lock;
public AutoCloseableLockWrapper(Lock l) {
this.lock = l;
}
#Override
public void lock() {
this.lock.lock();
}
#Override
public void lockInterruptibly() throws InterruptedException {
lock.lockInterruptibly();
}
#Override
public boolean tryLock() {
return lock.tryLock();
}
#Override
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
return lock.tryLock(time,unit);
}
#Override
public void unlock() {
lock.unlock();
}
#Override
public Condition newCondition() {
return lock.newCondition();
}
#Override
public void close() {
this.lock.unlock();
}
}
In my code I use it like this:
public class ReadWriteMap implements Map {
private HashMap map = new HashMap();
private ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
private Lock readLock = readWriteLock.readLock();
private Lock writeLock = readWriteLock.writeLock();
#Override
public int size() {
try (AutoCloseableLockWrapper autoCloseableLockWrapper = new AutoCloseableLockWrapper(readLock)) {
autoCloseableLockWrapper.lock();
return map.size();
}
}
#Override
public boolean isEmpty() {
try (AutoCloseableLockWrapper autoCloseableLockWrapper = new AutoCloseableLockWrapper(readLock)) {
autoCloseableLockWrapper.lock();
return map.isEmpty();
}
}
#Override
public boolean containsKey(Object key) {
try (AutoCloseableLockWrapper autoCloseableLockWrapper = new AutoCloseableLockWrapper(readLock)) {
autoCloseableLockWrapper.lock();
return map.containsKey(key);
}
}
...
}
I don't want to create wrapper in each method.
Is there way to combine single wrapper and try with resources ?
You are over-complicating your design. If your AutoCloseableLockWrapper intentionally exposes all operations supported by the underlying Lock, there is no point in making it private and adding delegation methods for each of Lock’s methods. You could simply make the Lock reference public to allow its use, or leave it off entirely, as the code which creates the wrapper already has a reference to the Lock.
All you want to do, is to support a single operation, unlock, which should be viewed as AutoCloseable.
A Java 8 solution may look like
import java.util.concurrent.locks.Lock;
public interface AutoUnlock extends AutoCloseable {
public static AutoUnlock lock(Lock lock) {
lock.lock();
return lock::unlock;
}
#Override
public void close(); // no checked exceptions
}
It can be used like:
Lock lock=…
// …
try(AutoUnlock u=AutoUnlock.lock(lock)) {
// critical code
}
// …
try(AutoUnlock u=AutoUnlock.lock(lock)) {
// critical code
}
If you worry about the instance creation (usually this is not an issue), you can re-use AutoCloseables:
AutoUnlock reusable=lock::unlock;
// …
lock.lock();
try(AutoUnlock u=reusable) {
// critical code
}
// …
lock.lock();
try(AutoUnlock u=reusable) {
// critical code
}
To me, it looks less clear since the lock(); and try statements are not syntactically coupled and could be separated by accident. But if the lock has a non-local scope, you could solve this by creating a utility method:
final Lock lockInstance; // this field name is to prevent confusion with the lock() method
final AutoUnlock reusable;
YourConstructor(Lock lock) {// you may get the Lock as a parameter
lockInstance=lock; // or create one here, right in the constructor
reusable=lockInstance::unlock;
}
AutoUnlock lock() {
lockInstance.lock();
return reusable;
}
void doSomething() {
// …
try(AutoUnlock u=lock()) {
// critical code
}
// …
try(AutoUnlock u=lock()) {
// critical code
}
}
I think, it’s not too hard to back-port this logic into Java 7 code, if needed.
You can use a factory method that returns a singleton. Nothing is forcing you to use a constructor.
BTW you should not call lock inside the try-block. That should have already happened in the "acquire the resource" phase (within the constructor in your current design, inside the factory method in my proposal).
I see that the above note is already posted on the Q&A page where you contributed your wrapper. The page already has very good content; I advise to study it well.
I'd prefer just creating a new lock (not a wrapper around a lock):
public class AutoReentrantLock implements AutoCloseable {
private final ReentrantLock lock = new ReentrantLock();
public AutoReentrantLock lock() {
lock.lock();
return this;
}
public void earlyUnlock() {
lock.unlock();
}
#Override
public void close() {
if(lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
}
Use like this:
private AutoReentrantLock consistencyLock = new AutoReentrantLock();
try(AutoReentrantLock lock = consistencyLock.lock()) {
// other code
}
Or a more complicated use case, where you unlock halfway:
private AutoReentrantLock consistencyLock = new AutoReentrantLock();
try(AutoReentrantLock lock = consistencyLock.lock()) {
// Place code here that gathers information (while under lock)
// but may exit early or throw exceptions
lock.earlyUnlock();
// ... followed by code that is slow that acts upon above gathered information.
}
We have some code that implements a cache. All of the methods have the synchronized keyword, and also use a ReadWriteLock internally. Simplified example:
private final ReadWriteLock _rwLock = new ReadWriteLock();
public synchronized void setItem(final UUID id, final Object someObjToCache) {
try {
_rwLock.writeLock().lock();
_innerCache.set(id, someObjToCache);
} finally {
_rwLock.writeLock().unlock();
}
}
public synchronized Object getItem(final UUID id) {
try {
_rwLock.readLock().lock();
return _innerCache.get(id);
} finally {
_rwLock.readLock().unlock();
}
}
Is there any benefit to using both of these locking techniques? I expect it to be a read-mostly cache, so I would think that just using the ReadWriteLock would be sufficient.
Yes, a ReadWriteLock should be sufficient. Using it with synchronized does not make much sense in this case: synchronized means that only one thread can execute any synchronized method at a time.
Using two locks will only help when you need to lock two resources at once.
I suspect you only need one lock, not two. If you used a concurrent collection you might not need either.
final Map<UUID, Object> cache = new ConcurrentHashMap<>();
public void setItem(UUID id, Object obj) { cache.put(id, obj); }
public Object getItem(UUID id) { return cache.get(id); }
In my class I have code like:
int counter1;
int counter2;
public void method1(){
if (counter1>0) {
...........do something
if (counter2>0) {
....do something else
}
}
public void method2() {
counter1=0;
counter2=0;
}
I need that both counters set together. I am afraid that OS can to method1 can be invoked after setting counter1 only. Does it possible?
Thanks.
Either use the synchronized keyword as the other answer suggest or use the ReentrantReadWriteLock if you have more reads than writes to the counter, for better performance. You can read about the lock here http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/ReentrantReadWriteLock.html
private int counter1;
private int counter2;
private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
private final Lock r = rwl.readLock();
private final Lock w = rwl.writeLock();
public void method1(){
r.lock();
try {
if (counter1>0) {
...........do something
if (counter2>0) {
....do something else
}
} finally { r.unlock(); }
}
public void method2() {
w.lock();
try {
counter1=0;
counter2=0;
} finally { w.unlock(); }
}
Sure, just use the synchronized keyword:
private final Object LOCK = new Object();
int counter1;
int counter2;
public void method1() {
synchronized(LOCK) {
if (counter1>0) {
...........do something
if (counter2>0) {
....do something else
}
}
}
public void method2() {
synchronized(LOCK) {
counter1=0;
counter2=0;
}
}
Some tips:
Use a private object for synchronization rather than marking a method synchronized. This prevents something external to you class from grabbing the lock and stalling things.
Make sure that you use the synchronized keyword everywhere, and make sure you always synchronize on the same object. If you forget to do either of those things, two processes can access the fields at the same time.
Beware of deadlocks. In a perfect world you'd write unit tests to ensure that locking is working the way you think it is.
Use a synchronized block or method to wrap access to the two counters, remember to use the same object to lock on.