I have a class member that is frequently read from one thread but rarely updated from another thread. How do I efficiently synchronize access to it? I imagine that if I just synchronize every read and write most read synchronizations will be wasted since the object doesn't change between them.
Including code example although it's pretty simple:
public class A {
public static class B {
}
private List<B> bs =
new ArrayList<>();
public void addB(B b) {
synchronized (this) {
bs.add(b);
}
}
public void run() {
while (true) {
List<B> bs;
synchronized (this) {
bs = new ArrayList<>(this.bs);
}
bs.forEach(b -> { /* do something */ });
}
}
}
assuming addB
and run
run from different threads.
ReadWriteLock
You can use ReadWriteLock
:
ReadWriteLock lock=new ReentrantReadWriteLock();
//Read access:
try{
lock.readLock().lock();
//Read access here
}finally{
lock.readLock().unlock()
}
//Write access
try{
lock.writeLock().lock();
//Write access here
}finally{
lock.writeLock().unlock()
This should minimize the overhead on readers as nothing is blocked when reading only.
synchronized
Another possibility is intrinsic synchronisation:
synchronized(LOCK){
//Read or write access here
}
If most of the work is done in a single thread and there is just a single reader thread (like in your scenario), this would be the most perfornant solution.
A third option could be to use thread safe data classes/data structures. This would not require you to do any synchronization by yourself. In your case, CopyOnWriteArrayList
would be a good option. It is optimized for many read and rare write accesses.
public class A {
public static class B {
}
private List<B> bs =
new CopyOnWriteArrayList<>();//important
public void addB(B b) {
//No synchronized needed
bs.add(b);
}
public void run() {
while (true) {
//No synchronized block needed, just iterate over bs as it is thread safe
bs.forEach(b -> { /* do something */ });
}
}
}
Whatever you choose, you should measure the performance impact if you care about it.
For measuring performance, you can use tools like JMH.