C#多线程技术总结(同步)
二、串行(同步):
1.lock、Monitor--注意锁定的对象必需是引用类型(string类型除外)
示例:
private static object syncObject = new object();
private static void TaskWork(object i)
{
Console.WriteLine("我是任务:{0}",i);
lock (syncObject)
{
Thread.Sleep(1000);
Console.WriteLine("我是任务:{0},线程ID:{1}",i,Thread.CurrentThread.ManagedThreadId);
}
try
{
Monitor.Enter(syncObject);
Console.WriteLine("我是任务:{0},线程ID:{1}", i, Thread.CurrentThread.ManagedThreadId);
}
finally
{
Monitor.Exit(syncObject);
}
}
//调用
Task.Factory.StartNew(TaskWork,1);
Task.Factory.StartNew(TaskWork, 2);
2.Interlocked
示例:
int i=1;
Interlocked.Increment(ref i); //增量+1=2;
Console.WriteLine("i当前的值:{0}", i); Interlocked.Decrement(ref i); //减量-1=0;
Console.WriteLine("i当前的值:{0}", i); Interlocked.Exchange(ref i, 2);//赋值=2;
Console.WriteLine("i当前的值:{0}",i); Interlocked.CompareExchange(ref i, 10, 2);//比较交换值,当i=2时,则将i赋值为10;
Console.WriteLine("i当前的值:{0}", i);
3.Mutex--可以实现进程间的同步,甚至是两个远程进程间的同步
示例:
var t1 = new Task(() =>
{
Console.WriteLine("我是第一个任务!");
Mutex m = new Mutex(false, "test");
m.WaitOne();
Console.WriteLine("第一个任务完成!");
m.ReleaseMutex();
}); var t2 = new Task(() =>
{
Console.WriteLine("我是第二个任务!");
Mutex m = new Mutex(false, "test");
m.WaitOne();
Console.WriteLine("第二个任务完成!");
m.ReleaseMutex();
}); t1.Start();
t2.Start();
4.ReaderWriterLock 、ReaderWriterLockSlim--如果在某一时刻资源并没有获取写的独占权,那么可以获得多个读的访问权,单个写入的独占权,如果某一时刻已经获取了写入的独占权,那么其它读取的访问权必须进行等待.
示例:
static ReaderWriterLock rwLock = new ReaderWriterLock();
static void Read(object state)
{
Console.WriteLine("我是读线程,线程ID是:{0}",Thread.CurrentThread.ManagedThreadId);
rwLock.AcquireReaderLock(Timeout.Infinite);//无限期等待,需要显式调用ReleaseReaderLock释放锁
var readList = state as IEnumerable<int>;
foreach (int item in readList)
{
Console.WriteLine("读取当前的值为:{0}", item);
Thread.Sleep(500);
}
Console.WriteLine("读完成,线程ID是:{0}", Thread.CurrentThread.ManagedThreadId);
rwLock.ReleaseReaderLock();
}
static void Write(object state)
{
Console.WriteLine("我是写线程,线程ID是:{0}", Thread.CurrentThread.ManagedThreadId);
rwLock.AcquireWriterLock(Timeout.Infinite); //无限期等待,需要显式调用ReleaseWriterLock释放锁
var writeList = state as List<int>;
int lastCount=writeList.Count();
for (int i = lastCount; i <= 10+lastCount; i++)
{
writeList.Add(i);
Console.WriteLine("写入当前值:{0}",i);
Thread.Sleep(500);
}
Console.WriteLine("写完成,线程ID是:{0}", Thread.CurrentThread.ManagedThreadId);
rwLock.ReleaseWriterLock();
}
//调用:
var rwList = new List<int>();
var t1 = new Thread(Write);
var t2 = new Thread(Read);
var t3 = new Thread(Write);
var t4 = new Thread(Read);
t1.Start(rwList);
t2.Start(rwList);
t3.Start(rwList);
t4.Start(rwList);
5.SynchronizationAttribute--确保某个类的实例在同一时刻只能被一个线程访问,类的定义要求:A.类上必需标记SynchronizationAttribute特性,B.类必需继承自System.ContextBoundObject对象
示例:
[Synchronization(SynchronizationAttribute.REQUIRED,true)]
public class Account : System.ContextBoundObject
{
private static int _balance;
public int Blance
{
get
{
return _balance;
}
} public Account()
{
_balance = 1000;
} public void WithDraw(string name,object money)
{
if ((int)money <= _balance)
{
Thread.Sleep(2000);
_balance = _balance - (int)money;
Console.WriteLine("{0} 取钱成功!余额={1}", name, _balance);
}
else
{
Console.WriteLine("{0} 取钱失败!余额不足!", name);
}
}
} //调用:
var account = new Account();
Parallel.Invoke(() =>
{
account.WithDraw("张三",600); }, () =>
{
account.WithDraw("李四",600);
});
6.MethodImplAttribute--使整个方法上锁,直到方法返回,才释放锁
示例:
public class Account
{
private static int _balance;
public int Blance
{
get
{
return _balance;
}
} public Account()
{
_balance = 1000;
} [MethodImpl(MethodImplOptions.Synchronized)]
public void WithDraw(string name,object money)
{
if ((int)money <= _balance)
{
Thread.Sleep(2000);
_balance = _balance - (int)money;
Console.WriteLine("{0} 取钱成功!余额={1}", name, _balance);
}
else
{
Console.WriteLine("{0} 取钱失败!余额不足!", name);
}
}
} //调用
var account = new Account();
Parallel.Invoke(() =>
{
account.WithDraw("张三",600); }, () =>
{
account.WithDraw("李四",600);
});
7.AutoResetEvent、ManualResetEvent、ManualResetEventSlim--调用WaitOne、WaitAny或WaitAll来使线程等待事件,调用Set方法发送信号,事件将变为终止状态,等待的线程被唤醒
示例:
AutoResetEvent arEvent = new AutoResetEvent(false);//默认为无信号,处于非终止状态
Task.Factory.StartNew((o) => {
for (int i = 1; i <= 10; i++)
{
Console.WriteLine("循环第{0}次",i);
}
arEvent.Set();//发送信号,处于终止状态
},arEvent); arEvent.WaitOne();//等待信号,收到信号后则继续下面的执行 Console.WriteLine("我是主线程,我继续执行!");
Console.Read();
8.Sempaphore、SemaphoreSlim(不可跨进程)--信号量,可实现线程、进程间同步
示例:
public class WashRoom
{
private readonly Semaphore sem; public WashRoom(int maxUseableCount)
{
sem = new Semaphore(maxUseableCount, maxUseableCount, "WC");
} public void Use(int i)
{
Task.Factory.StartNew(() =>
{
Console.WriteLine("第{0}个人等待进入", i);
// WaitOne:如果还有“空位”,则占位,如果没有空位,则等待;
sem.WaitOne();
Console.WriteLine("第{0}个人成功进入,使用中", i);
// 模拟线程执行了一些操作
Thread.Sleep(100);
Console.WriteLine("第{0}个人用完,离开了", i);
// Release:释放一个“空位”
sem.Release();
});
}
} //调用:
var wc = new WashRoom(5);
for (int i = 1; i <= 7; i++)
{
wc.Use(i);
}
9.Barrier--屏障,使多个任务能够采用并行方式依据某种算法在多个阶段中协同工作,即:将一个阶段的事情分成多个线程来异步执行,执行完毕后再同时进入下一个阶段
示例:
int taskSize = 5;
Barrier barrier = new Barrier(taskSize, (b) =>
{
Console.WriteLine(string.Format("{0}当前阶段编号:{1}{0}", "-".PadRight(15, '-'), b.CurrentPhaseNumber));
}); var tasks = new Task[taskSize]; for (int i = 0; i < taskSize; i++)
{
tasks[i] = Task.Factory.StartNew((n) =>
{
Console.WriteLine("Task : #{0} ----> 处理了第一部份数据。", n);
barrier.SignalAndWait(); Console.WriteLine("Task : #{0} ----> 处理了第二部份数据。", n);
barrier.SignalAndWait(); Console.WriteLine("Task : #{0} ----> 处理了第三部份数据。", n);
barrier.SignalAndWait(); }, i);
} Task.WaitAll(tasks);
10.SpinLock--自旋锁,仅限锁定的时间较短
示例:
SpinLock sLock = new SpinLock();
int num = 0;
Action action = () =>
{
bool lockTaken = false;
for (int i = 0; i < 10; i++)
{
lockTaken = false;
try
{
sLock.Enter(ref lockTaken);
Console.WriteLine("{0}+1={1} ---线程ID:[{2}]", num, ++num,Thread.CurrentThread.ManagedThreadId);
Thread.Sleep(new Random().Next(9));
}
finally
{
//真正获取之后,才释放
if (lockTaken) sLock.Exit();
}
}
}; //多线程调用:
Parallel.Invoke(action, action, action);
Console.WriteLine("合计:{0}", num);
11.SpinWait--自旋等待,轻量级
Thread.Sleep(1000);//线程等待1S;
Console.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")); SpinWait.SpinUntil(() => false, 1000);//自旋等待1S
Console.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")); Thread.SpinWait(100000);//指定CPU的循环次数,时间间隔处决于处理器的运行速度,一般不建议使用
Console.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"));
12.CountdownEvent--与Sempaphore功能类似,但CountdownEvent支持动态调整信号计数
示例:
static void TimeLimitShopping(int custCount,int times,CountdownEvent countdown)
{
var customers = Enumerable.Range(1, custCount);
foreach (var customer in customers)
{
int currentCustomer = customer;
Task.Factory.StartNew(()=>
{
SpinWait.SpinUntil(() => false, 1000);
Console.WriteLine("第{0}波客户购买情况:Customer-{1}-已购买.", times, currentCustomer);
countdown.Signal();
});
//countdown.AddCount();
}
} //调用:
var countdown = new CountdownEvent(5);
TimeLimitShopping(5, 1, countdown);
countdown.Wait(); countdown.Reset(10);
TimeLimitShopping(10, 2, countdown);
countdown.Wait(); countdown.Reset(20);
TimeLimitShopping(20, 3, countdown);
countdown.Wait();
最后分享在System.Collections.Concurrent命名空间下的几个并发集合类:
ConcurrentBag<T>:表示线程安全的无序集合;
ConcurrentDictionary<T>:表示线程安全的多个键值对集合;
ConcurrentQueue<T>:表示线程安全的先进先出集合;
ConcurrentStack<T>:表示线程安全的后进先出集合;
线程的几个状态(以下图片来源于这篇文章:http://www.cnblogs.com/edisonchou/p/4848131.html):

参考以下相关文章:
C#多线程技术总结(同步)的更多相关文章
- C#多线程之线程同步篇1
在多线程(线程同步)中,我们将学习多线程中操作共享资源的技术,学习到的知识点如下所示: 执行基本的原子操作 使用Mutex构造 使用SemaphoreSlim构造 使用AutoResetEvent构造 ...
- iOS多线程技术方案
iOS多线程技术方案 目录 一.多线程简介 1.多线程的由来 2.耗时操作的模拟试验 3.进程和线程 4.多线程的概念及原理 5.多线程的优缺点和一个Tip 6.主线程 7.技术方案 二.Pthrea ...
- iOS开发之多线程技术
本篇争取一篇讲清讲透,依然将通过四大方面清晰的对iOS开发中多线程的用法进行详尽的讲解: 一.什么是多线程 1)多线程执行原理 2)线程与进程 3)多线程的优缺点 二.我们为什么要用多线程编程技术 三 ...
- iOS多线程技术
iOS多线程技术主要分配NSThread.NSOperation和GCD.下边来简单的介绍一下吧. 随性一点,就不按照顺序来了.所以先介绍一下NSOperation. ---------------- ...
- iOS的三种多线程技术NSThread/NSOperation/GCD
1.iOS的三种多线程技术 1.NSThread 每个NSThread对象对应一个线程,量级较轻(真正的多线程) 2.以下两点是苹果专门开发的"并发"技术,使得程序员可以不再去关心 ...
- 多线程技术在iOS开发中的使用
进程和线程 要使用多线程,首先需要理解进程和线程这2个概念.这里我简单的说一下. 所谓进程对应的是一个应用程序,负责开辟内存空间供应用程序使用,但是进程不能执行任务(指令).一个进程至少包含一条线程, ...
- Java多线程技术学习笔记(二)
目录: 线程间的通信示例 等待唤醒机制 等待唤醒机制的优化 线程间通信经典问题:多生产者多消费者问题 多生产多消费问题的解决 JDK1.5之后的新加锁方式 多生产多消费问题的新解决办法 sleep和w ...
- C# 多线程(二) 线程同步基础
本系列的第一篇简单介绍了线程的概念以及对线程的一些简单的操作,从这一篇开始讲解线程同步,线程同步是多线程技术的难点.线程同步基础由以下几个部分内容组成 1.同步要领(Synchronization E ...
- IOS 多线程,线程同步的三种方式
本文主要是讲述 IOS 多线程,线程同步的三种方式,更多IOS技术知识,请登陆疯狂软件教育官网. 一般情况下我们使用线程,在多个线程共同访问同一块资源.为保护线程资源的安全和线程访问的正确性. 在IO ...
- VC中利用多线程技术实现线程之间的通信
当前流行的Windows操作系统能同时运行几个程序(独立运行的程序又称之为进程),对于同一个程序,它又可以分成若干个独立的执行流,我们称之为线程,线程提供了多任务处理的能力.用进程和线程的观点来研究软 ...
随机推荐
- diff详解,读懂diff结果
1.概述 本文将要讨论的是diff命令,diff用来比较两个文件.当然文件比较的工具很多,windows系统下面就有不错的工具可以使用,例如常用的Beyond Compare,WinMerge都是图形 ...
- Javascript自己动手实现getter/setter
虽然ES5中为我们提供了Object.defineProperty方法来设置getter与setter,但此原生方法使用起来并不方便,我们何不自己来实现一个类,只要继承该类并遵循一定的规范就可以拥有媲 ...
- Java提高篇(三二)-----List总结
前面LZ已经充分介绍了有关于List接口的大部分知识,如ArrayList.LinkedList.Vector.Stack,通过这几个知识点可以对List接口有了比较深的了解了.只有通过归纳总结的知识 ...
- SVM-线性可分支持向量机
SVM-线性可分支持向量机 如果您想体验更好的阅读:请戳这里littlefish.top 函数间隔和几何间隔 给定线性可分训练数据集,通过间隔最大化或等价地求解相应的凸二次规划问题学习得到的分离超平面 ...
- Lucene系列-概述
为了生存,就得干一行爱一行.那就学习下lucene吧. 全文检索介绍 流程: 建索引 准备待搜索文档 文档分词:将文档分成一个个单独的单词,去除标点符号.停词(无意义的冠词介词等),得到token 语 ...
- Java序列化格式详解
RPC的世界,由于涉及到进程间网络远程通信,不可避免的需要将信息序列化后在网络间传送,序列化有两大流派: 文本和二进制. 文本序列化 序列化的实现有很多方式,在异构系统中最常用的就是定义成人类可读的文 ...
- 奇怪的BUG
熟语说“常在河边走,哪能不湿鞋”,在现实中我想说:“代码写多了,总会遇到奇怪的bug”,遇到bug不可怕,可怕的是不自己不知道这么解决,有些bug能当时解决,有些在自己知识水平提高后知道如何解决.还有 ...
- EF架构~引入规约(Specification)模式,让程序扩展性更强
回到目录 规约(Specification)模式:第一次看到这东西是在microsoft NLayer项目中,它是微软对DDD的解说,就像petshop告诉了我们MVC如何使用一样,这个规约模式最重要 ...
- [源码解析]HashMap和HashTable的区别(源码分析解读)
前言: 又是一个大好的周末, 可惜今天起来有点晚, 扒开HashMap和HashTable, 看看他们到底有什么区别吧. 先来一段比较拗口的定义: Hashtable 的实例有两个参数影响其性能:初始 ...
- WPF入门教程系列十三——依赖属性(三)
四. 只读依赖属性 在以前在对于非WPF的功能来说,对于类的属性的封装中,经常会对那些希望暴露给外界只读操作的字段封装成只读属性,同样在WPF中也提供了只读属性的概念,如一些 WPF控件的依赖属性是只 ...