我最近使用过Apache Commons-IO的类CountingInputStream
。它只是通过更新计数器字段来跟踪读取的字节数。
我注意到它使用synchronized
关键字更新了其计数器。我能找到的最好的来源是IO-201,但它没有解释原因。
我在一些地方读到Apache Commons代码质量很好,但我现在想知道为什么他们在InputStream中有同步方法。我不认为线程安全是流上的有用属性,也不认为IO-201的评论员。
鉴于我没有同时访问InputStream,是否有任何有效理由使其方法同步?或者是否有一个有效的用例来同时访问一个不会产生数据垃圾的InputStream?
答案 0 :(得分:4)
鉴于我没有同时访问
public class PartyMaker { private readonly SemaphoreSlim _slowStuffSemaphore = new SemaphoreSlim(1, 1); private readonly ConcurrentDictionary<int, int> _requestCounts = new ConcurrentDictionary<int, int>(); private readonly ConcurrentDictionary<int, DateTime> _cache = new ConcurrentDictionary<int, DateTime>(); public async Task<DateTime> ShakeItAsync(Argument argument) { var key = argument.GetHashCode(); DateTime result; try { if (!_requestCounts.ContainsKey(key)) { _requestCounts[key] = 1; } else { ++_requestCounts[key]; } var needNewRequest = _requestCounts[key] == 1; await _slowStuffSemaphore.WaitAsync().ConfigureAwait(false); if (!needNewRequest) { _cache.TryGetValue(key, out result); return result; } _cache.TryAdd(key, default(DateTime)); result = await ShakeItSlowlyAsync().ConfigureAwait(false); _cache[key] = result; return result; } finally { _requestCounts[key]--; if (_requestCounts[key] == 0) { int temp; _requestCounts.TryRemove(key, out temp); _cache.TryRemove(key, out result); } _slowStuffSemaphore.Release(); } } private async Task<DateTime> ShakeItSlowlyAsync() { await Task.Delay(TimeSpan.FromSeconds(1)).ConfigureAwait(false); return DateTime.UtcNow; } } public class Argument { public Argument(int value) { Value = value; } public int Value { get; } public override int GetHashCode() { return Value.GetHashCode(); } }
,是否有任何正当理由使其方法同步?
不,没有正当理由让您对仅从单个线程访问的对象使用同步方法。话虽这么说,你正在使用做同步的第三方代码来保护可变状态(InputStream
字段),所以除了自己实现它之外你没有太多选择。
或者是否有一个有效的用例同时访问
count
不会产生数据垃圾?
InputStream
?可能不是。一个InputStream
?当然......在一个线程中,我反复调用CountingInputStream
来使用流,而在另一个线程中,我反复调用CountingInputStream.read()
来更新我的UI以显示我读过的行数。