如何高效同步很少变化的数据?
How to efficiently synchronize rarely changed data?
我有一个 class 成员,它经常从一个线程读取但很少从另一个线程更新。如何有效地同步对它的访问?我想,如果我只是同步每个读取和写入,那么大多数读取同步将被浪费,因为对象不会在它们之间更改。
包括代码示例,虽然它很简单:
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 */ });
}
}
}
假设 addB
和 run
运行 来自不同的线程。
ReadWriteLock
您可以使用 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()
这应该最大限度地减少 reader 的开销,因为只读时没有任何阻塞。
synchronized
另一种可能性是内在同步:
synchronized(LOCK){
//Read or write access here
}
如果大部分工作在单个线程中完成并且只有一个 reader 线程(如您的场景),这将是最高效的解决方案。
使用线程安全类
第三种选择可能是使用线程安全数据classes/data 结构。这不需要您自己进行任何同步。在您的情况下,CopyOnWriteArrayList
将是一个不错的选择。它针对许多读取和罕见的写入访问进行了优化。
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 */ });
}
}
}
无论你选择什么,如果你关心它,你应该衡量性能影响。
要衡量性能,您可以使用 JMH 等工具。
您可以使用并发包中的 ReentrantReadWriteLock。
我有一个 class 成员,它经常从一个线程读取但很少从另一个线程更新。如何有效地同步对它的访问?我想,如果我只是同步每个读取和写入,那么大多数读取同步将被浪费,因为对象不会在它们之间更改。
包括代码示例,虽然它很简单:
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 */ });
}
}
}
假设 addB
和 run
运行 来自不同的线程。
ReadWriteLock
您可以使用 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()
这应该最大限度地减少 reader 的开销,因为只读时没有任何阻塞。
synchronized
另一种可能性是内在同步:
synchronized(LOCK){
//Read or write access here
}
如果大部分工作在单个线程中完成并且只有一个 reader 线程(如您的场景),这将是最高效的解决方案。
使用线程安全类
第三种选择可能是使用线程安全数据classes/data 结构。这不需要您自己进行任何同步。在您的情况下,CopyOnWriteArrayList
将是一个不错的选择。它针对许多读取和罕见的写入访问进行了优化。
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 */ });
}
}
}
无论你选择什么,如果你关心它,你应该衡量性能影响。
要衡量性能,您可以使用 JMH 等工具。
您可以使用并发包中的 ReentrantReadWriteLock。