.Net 知识点

.Net 知识点

Multi Thread (多线程)

多线程下解决资源竞争的7种方法

  1. 临界区 Lock

其实是临界区(Monitor)的一个语法糖,通过对多线程的串行化来访问公共资源或一段代码,速度快,适合控制数据访问。

private static object obj = new object();
private static int lockInt;
private static void LockIntAdd()
{
    for (var i = 0; i < runTimes; i++)
    {
        lock (obj)
        {
            lockInt++;
        }
    }
}
  1. 互斥量 Mutex

为协调共同对一个共享资源的单独访问而设计的。在System.Threading命名空间下,Mutex其实就是互斥量,互斥量不单单能处理多线程之间的资源竞争,还能处理进程之间的资源竞争,功能是比较强大的,但是开销也很大,性能比较低。

private static Mutex mutex = new Mutex();
private static int mutexInt;
private static void MutexIntAdd()
{
    for (var i = 0; i < runTimes; i++)
    {
        mutex.WaitOne();
        mutexInt++;
        mutex.ReleaseMutex();
    }
}
  1. 信号量 Semaphore

为控制一个具有有限数量用户资源而设计。

private static Semaphore sema = new Semaphore(1, 1);
private static int semaphoreInt;
private static void SemaphoreIntAdd()
{
    for (var i = 0; i < runTimes; i++)
    {
        sema.WaitOne();
        semaphoreInt++;
        sema.Release();
    }
}
  1. 事件 AutoResetEvent

用来通知线程有一些事件已发生,从而启动后继任务的开始。

public static AutoResetEvent autoResetEvent = new AutoResetEvent(true);
private static int autoResetEventInt;
private static void AutoResetEventIntAdd()
{
    for (var i = 0; i < runTimes; i++)
    {
        if (autoResetEvent.WaitOne())
        {
            autoResetEventInt++;
            autoResetEvent.Set();
        }
    }
}
  1. 读写锁 ReaderWriterLockSlim

这种锁允许在有其他程序正在写的情况下读取资源,所以如果资源允许脏读,用这个比较合适。

private static ReaderWriterLockSlim LockSlim = new ReaderWriterLockSlim();
private static int lockSlimInt;
private static void LockSlimIntAdd()
{
    for (var i = 0; i < runTimes; i++)
    {
        LockSlim.EnterWriteLock();
        lockSlimInt++;
        LockSlim.ExitWriteLock();
    }
}
  1. 原子锁 Interlocked.CompareExchange

通过原子操作Interlocked.CompareExchange实现“无锁”竞争。

private static int isLock;
private static int ceInt;
private static void CEIntAdd()
{
    //long tmp = 0;
    for (var i = 0; i < runTimes; i++)
    {
        while (Interlocked.CompareExchange(ref isLock, 1, 0) == 1) { Thread.Sleep(1); }

        ceInt++;
        Interlocked.Exchange(ref isLock, 0);
    }
}
  1. 原子性操作 Interlocked.Increment

这是一种特例,野外原子性操作本身天生线程安全,所以无需加锁。

private static int atomicInt;
private static void AtomicIntAdd()
{
    for (var i = 0; i < runTimes; i++)
    {
        Interlocked.Increment(ref atomicInt);
    }
}
  1. 使用ConCurrent线程安全的集合
  • ConCurrentQueue
  • Enqueue:在队尾插入元素
  • TryDequeue:尝试删除队头元素,并通过out参数返回
  • TryPeek:尝试将对头元素通过out参数返回,但不删除该元素
  • ConcurrentStack
  • Push:向栈顶插入元素
  • TryPop:从栈顶弹出元素,并且通过out 参数返回
  • TryPeek:返回栈顶元素,但不弹出
  • ConcurrentDictionary
  • AddOrUpdate:如果键不存在,方法会在容器中添加新的键和值,如果存在,则更新现有的键和值。
  • GetOrAdd:如果键不存在,方法会向容器中添加新的键和值,如果存在则返回现有的值,并不添加新值。
  • TryAdd:尝试在容器中添加新的键和值。
  • TryGetValue:尝试根据指定的键获得值。
  • TryRemove:尝试删除指定的键。
  • TryUpdate:有条件的更新当前键所对应的值。
  • GetEnumerator:返回一个能够遍历整个容器的枚举器
  • ConcurrentBag 一个无序的数据结构集,当不需要考虑顺序时非常有用
  • Add:向集合中插入元素
  • TryTake:从集合中取出元素并删除
  • TryPeek:从集合中取出元素,但不删除该元素
  • BlockingCollection 与经典的阻塞队列数据结构类似
  • Add :向容器中插入元素
  • TryTake:从容器中取出元素并删除
  • TryPeek:从容器中取出元素,但不删除。
  • CompleteAdding:告诉容器,添加元素完成。此时如果还想继续添加会发生异常
  • IsCompleted:告诉消费线程,生产者线程还在继续运行中,任务还未完成
原文地址:https://www.cnblogs.com/Nine4Cool/p/13721915.html