一、
StringBuilder
对象在程序中经常被用到,一般是希望在拼接字符串时获得更好的性能;
但是重复构造StringBuilder
对象本身也有性能损失,于是有了StringBuilder对象池
二、
- 对象池模型创建并拥有固定数量的对象,当程序需要一个新的对象时,如果对象池中有空闲对象,则立即返回,否则才创建新的该类对象。
- 当一个对象不再被使用时,其应该应该将其放回对象池,以便后来的程序使用。由于系统资源有限,一个对象池模型应该指定其可容纳的最大对象数量。
- 当达到该数量时,如果仍然有对象创建请求,则抛出异常或者阻塞当前调用线程,直到一个对象被放回对象池中。
网上抄的
三、
基本思路:
- 使用
ConcurrentQueue<,>
保证并发 - 利用
using
语法糖回收对象 - 使用
Interlocked.Increment
计数(Queue
中的对象会被取出,不能直接用Length
计数) - 当超过最大值时,不抛异常,直接创建一个新的对象,但也不回收该对象
四、
/// <summary>
/// <seealso cref="StringBuilder"/>对象池
/// </summary>
static class StringBuilderPool
{
/// <summary>
/// 对象池最大容量大小
/// </summary>
public const int MAX_CAPACITY = 63;
// 对象缓存
private static readonly ConcurrentQueue<StringBuilder> _cache = new ConcurrentQueue<StringBuilder>();
// 计数器
private static int _counter = 0;
/// <summary>
/// 弹出 <seealso cref="StringBuilder"/> 对象
/// </summary>
public static IDisposable Pop(out StringBuilder builder)
{
// 尝试从缓存中获取对象
_cache.TryDequeue(out builder);
if (builder != null)
{
return new Recyclable(builder); // 返回可回收对象
}
// 计数器超过池最大容量,或计数器+1超过池最大容量,则直接返回新的 StringBuilder 且不回收
if (_counter > MAX_CAPACITY || Interlocked.Increment(ref _counter) > MAX_CAPACITY)
{
builder = new StringBuilder();
return NoRecycle; //不回收
}
builder = new StringBuilder();
return new Recyclable(builder);
}
// 不执行回收操作的空对象
private static readonly IDisposable NoRecycle = new Recyclable(null);
/// <summary>
/// 可回收 <seealso cref="StringBuilder"/> 的对象
/// </summary>
class Recyclable : IDisposable
{
/// <summary>
/// 初始化对象
/// </summary>
/// <param name="builder">待回收的 <seealso cref="StringBuilder"/> 对象</param>
public Recyclable(StringBuilder builder) => _stringBuilder = builder;
// 待回收的对象
private StringBuilder _stringBuilder;
/// <summary>
/// 回收对象
/// </summary>
public void Dispose()
{
// 将 _stringBuilder 修改为null 并返回 _stringBuilder 的原始值
var builder = Interlocked.Exchange(ref _stringBuilder, null);
if (builder != null)
{
builder.Clear();
_cache.Enqueue(builder); //回收
}
}
// 析构函数
~Recyclable() => Dispose();
}
}
五、
调用
using (StringBuilderPool.Pop(out var builder))
{
for (var i = 0; i < 10; i++)
{
builder.Append(i);
builder.AppendLine(",");
}
return builder.ToString();
}
网友评论