gpt4 book ai didi

java - Java中的并发读/写缓冲区

转载 作者:塔克拉玛干 更新时间:2023-11-03 03:46:56 25 4
gpt4 key购买 nike

我正在尝试实现一个读/写缓冲区类,在该类中它可以支持多个写程序和读程序,并且在写程序编写缓冲区的同时,读程序可以同时读取缓冲区。这是我的代码,到目前为止我还没有看到任何问题,但是我不确定100%是否是线程安全的或者是否有更好的方法。

public class Buffer{
private StringBuilder sb = new StringBuilder();
private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
private Random random = new Random();

public void read(){
try{
lock.readLock().lock();
System.out.println(sb.toString());
} finally{
lock.readLock().unlock();
}
}
public void write(){
try{
lock.writeLock().lock();
sb.append((char)(random.nextInt(26)+'a'));
} finally{
lock.writeLock().unlock();
}
}
}

最佳答案

多线程安全没有任何问题!读写锁保护对StringBuilder的访问,并且代码干净且易于阅读。

通过使用ReentrantReadWriteLock,实际上可以最大程度地提高实现更高并发度的机会,因为多个读取器可以一起进行,因此,这比使用普通的旧同步方法更好。但是,与问题中所陈述的相反,该代码不允许作者在读者阅读的同时进行写作。但是,这本身并不一定是问题。

读者在继续操作之前会获得读锁。编写者在继续操作之前已获得写锁定。读锁定规则允许在没有写锁定时获取一个(但如果有一些读锁定,即如果有更多 Activity 的读取器,则可以)。只有当没有其他锁(没有读取器,没有写入器)时,写入锁的规则才允许获取一个。因此,允许多个读者,但只有一个作家。

唯一可能需要的更改是将锁初始化代码更改为此:

private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(true);

正如问题中给出的原始代码一样,该锁也不需要公平。通过上述更改,可以确保“线程使用近似到达顺序的策略争用进入。释放写锁定时,将为等待时间最长的单个写程序分配写锁定,或者如果读取器的等待时间超过任何写者,都将为这组阅读器分配读锁。当构造为不公平时,锁的进入顺序不必为到达顺序。” (摘自 http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/locks/ReentrantReadWriteLock.html)

另请参见以下内容(来自同一来源):

ReentrantReadWriteLocks可用于改善某些Collections的某些使用中的并发性。仅当预期集合很大,由读取器线程而不是写入器线程访问的集合更多且需要的操作开销超过同步开销时,这通常才是值得的。例如,这是一个使用TreeMap的类,该类应该很大并且可以同时访问。
class RWDictionary {
private final Map<String, Data> m = new TreeMap<String, Data>();
private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
private final Lock r = rwl.readLock();
private final Lock w = rwl.writeLock();

public Data get(String key) {
r.lock(); try { return m.get(key); } finally { r.unlock(); }
}
public String[] allKeys() {
r.lock(); try { return m.keySet().toArray(); } finally { r.unlock(); }
}
public Data put(String key, Data value) {
w.lock(); try { return m.put(key, value); } finally { w.unlock(); }
}
public void clear() {
w.lock(); try { m.clear(); } finally { w.unlock(); }
}
}

API文档的节选特别注重性能。在您的特定情况下,我无法评论您是否满足“大集合”条件,但是我可以说,输出到控制台比线程安全机制开销要花更多的时间。无论如何,从逻辑的角度来看,您使用ReentrantReadWriteLocks是完全合理的,并且是线程安全的。这是不错的代码:-)

注释1(关于在原始问题的注释中找到的关于异常(exception)的回答问题):
取自 http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/locks/Lock.html
lock()获取锁。
如果该锁不可用,则出于线程调度目的,当前线程将被禁用,并处于 hibernate 状态,直到获得该锁为止。

锁实现可能能够检测到锁的错误使用,例如可能导致死锁的调用,并且在这种情况下可能引发(未经检查的)异常。该Lock实现必须记录情况和异常类型。

ReentrantReadWriteLock.ReadLock( http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/locks/ReentrantReadWriteLock.ReadLock.html)或ReentrantReadWriteLock.WriteLock( http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/locks/ReentrantReadWriteLock.WriteLock.html)的相关文档中未提供此类异常的指示。

注意2:虽然对StringBuilder的访问受锁保护,但System.out不 protected 。特别是,多个读取器可能会同时读取值并尝试同时输出。这也是可以的,因为对System.out.println()的访问是同步的。

注意3:如果您要禁止多个活跃的写作者,但允许一个写作者和一个或多个读者同时处于 Activity 状态,则可以简单地使用读锁来完全跳过,即删除lock.readLock()。lock();。和lock.readLock()。unlock();在您的代码中。但是,在这种特殊情况下,这将是错误的。您需要停止并发读写StringBuilder。

关于java - Java中的并发读/写缓冲区,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13588003/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com