Tho*_*mas 6 java multithreading synchronized
有多个线程,比如B,C和D,每个线程都以高频率将小数据包写入缓冲区.他们拥有自己的缓冲区,没有其他人写过它.写作必须尽可能快,我已经确定使用synchronized它会让它变得无法接受.
缓冲区只是字节数组,以及第一个自由元素的索引:
byte[] buffer;
int index;
public void write(byte[] data) {
// some checking that the buffer won't overflow... not important now
System.arraycopy(data, 0, buffer, index, data.length);
index += data.length;
}
Run Code Online (Sandbox Code Playgroud)
每隔一段时间,线程A就会将每个人的缓冲区刷新到文件中.如果这部分有一些开销可以,所以synchronized在这里使用是没有问题的.
现在麻烦的是,一些其他线程可能正在写入缓冲区,而线程A正在刷新它.这意味着两个线程会index在同一时间尝试写入.这会导致数据损坏,我想阻止,但不使用synchronized该write()方法.
我已经感觉到,使用正确的操作顺序,可能还有一些volatile领域,这一定是可能的.有什么好主意吗?
您是否尝试过使用同步的解决方案,并发现它的性能不够好?你说你已经确定它的速度慢得令人无法接受 - 速度有多慢,你是否已经有了性能预算?通常情况下,获得无争议的锁是非常便宜的,所以我不认为这是一个问题.
有可能是一些聪明的无锁的解决方案-但它很可能是显著比每当你需要访问共享数据只是同步更加复杂.我知道无锁编码风靡一时,并且在你可以做到的时候可以很好地扩展 - 但如果你有一个线程干扰另一个数据,那么很难安全地进行编码.为了清楚起见,当我可以使用专家创建的高级抽象时,我喜欢使用无锁代码 - 比如.NET 4中的Parallel Extensions.我只是不喜欢使用像volatile这样的低级抽象,如果我可以帮忙.
尝试锁定并对其进行基准测试.找出可接受的性能,并将简单解决方案的性能与该目标进行比较.
当然,一种选择是重新设计......冲洗是否必须在不同的线程中主动发生?个别编写器线程是否可以定期将缓冲区切换到刷新线程(并启动不同的缓冲区)?这会让事情变得简单得多.
编辑:关于你的"冲洗信号"的想法 - 我一直在思考类似的问题.但是你需要注意你是如何做到的,这样即使一个线程需要很长时间来处理它正在做的事情,信号也不会丢失.我建议你让线程A发布一个"刷新计数器"......并且每个线程在最后一次刷新时保留自己的计数器.
编辑:刚刚意识到这是Java,而不是C# - 更新:)
用于AtomicLong.incrementAndGet()从线程A递增,以及AtomicLong.get()从其他线程读取.然后在每个线程中,比较您是否"最新",并在必要时刷新:
private long lastFlush; // Last counter for our flush
private Flusher flusher; // The single flusher used by all threads
public void write(...)
{
long latestFlush = flusher.getCount(); // Will use AtomicLong.get() internally
if (latestFlush > lastFlush)
{
flusher.Flush(data);
// Do whatever else you need
lastFlush = latestFlush; // Don't use flusher.getCount() here!
}
// Now do the normal write
}
Run Code Online (Sandbox Code Playgroud)
请注意,这假设您只需要在Write方法中检查是否需要刷新.显然情况可能并非如此,但希望你能适应这个想法.
| 归档时间: |
|
| 查看次数: |
3611 次 |
| 最近记录: |