https://www.cnblogs.com/zhili/archive/2012/07/21/ThreadsSynchronous.html 线程同步html
1.c# 的原子操做 能够防止并发。Interlocked数据库
(以保证这段代码的原子性(atomic)操做,即:要么不执行这段代码,要么将这段代码所有执行完毕。防止并发污染数据)c#
2.线程的优先级安全
static void Main(string[] args) { Thread threadA = new Thread(ThreadMethod); //执行的必须是无返回值的方法 threadA.Name = "A"; Thread threadB = new Thread(ThreadMethod); //执行的必须是无返回值的方法 threadB.Name = "B"; threadA.Priority = ThreadPriority.Highest; threadB.Priority = ThreadPriority.BelowNormal; threadB.Start(); threadA.Start(); Thread.CurrentThread.Name = "C"; ThreadMethod(new object()); Console.ReadKey(); } public static void ThreadMethod(object parameter) { for (int i = 0; i < 500; i++) { Console.Write(Thread.CurrentThread.Name); } }
Thread.CurrentThread.Name = "C"; 当前线程多线程
3. 线程同步并发
什么是线程安全:性能
线程安全是指在当一个线程访问该类的某个数据时,进行保护,其余线程不能进行访问直到该线程读取完,其余线程才可以使用。不会出现数据不一致或者数据污染。this
线程有可能和其余线程共享一些资源,好比,内存,文件,数据库等。当多个线程同时读写同一份共享资源的时候,可能会引发冲突。这时候,咱们须要引入线程“同步”机制,即各位线程之间要有个先来后到,不能一窝蜂挤上去抢做一团。线程同步的真实意思和字面意思刚好相反。线程同步的真实意思,实际上是“排队”:几个线程之间要排队,一个一个对共享资源进行操做,而不是同时进行操做。atom
解决线程同步的方法:spa
3.0 锁
static void Main(string[] args) { Program pro1 = new Program(); Program pro2 = new Program(); Thread threadA = new Thread(pro1.ThreadMethod); //执行的必须是无返回值的方法 threadA.Name = "王文建"; Thread threadB = new Thread(pro2.ThreadMethod); //执行的必须是无返回值的方法 threadB.Name = "生旭鹏"; threadA.Start(); threadB.Start(); Console.ReadKey(); } public void ThreadMethod(object parameter) { lock (this) { for (int i = 0; i < 10; i++) { Console.WriteLine("我是:{0},我循环{1}次", Thread.CurrentThread.Name, i); Thread.Sleep(300); } } }
lock(this) 锁定 当前实例对象,若是有多个类实例的话,lock锁定的只是当前类实例,对其它类实例无影响。全部不推荐使用。
lock(typeof(Model))锁定的是model类的全部实例。 这里的Model是指某个类名。
lock(obj)锁定的对象是全局的私有化静态变量。外部没法对该变量进行访问。
lock 确保当一个线程位于代码的临界区时,另外一个线程不进入临界区。若是其余线程试图进入锁定的代码,则它将一直等待(即被阻止),直到该对象被释放。
因此,lock的结果好很差,仍是关键看锁的谁,若是外边能对这个谁进行修改,lock就失去了做用。
因此,通常状况下,使用私有的、静态的而且是只读的对象。
总结:
一、lock的是必须是引用类型的对象,string类型除外。
二、lock推荐的作法是使用静态的、只读的、私有的对象。
三、保证lock的对象在外部没法修改才有意义,若是lock的对象在外部改变了,对其余线程就会畅通无阻,失去了lock的意义。
不能锁定字符串,锁定字符串尤为危险,由于字符串被公共语言运行库 (CLR)“暂留”。 这意味着整个程序中任何给定字符串都只有一个实例,就是这同一个对象表示了全部运行的应用程序域的全部线程中的该文本。所以,只要在应用程序进程中的任何位置处具备相同内容的字符串上放置了锁,就将锁定应用程序中该字符串的全部实例。一般,最好避免锁定 public 类型或锁定不受应用程序lock块内控制的对象实例。例如,若是该实例能够被公开访问,则 lock(this) 可能会有问题,由于不受控制的代码也可能会锁定该对象。这可能致使死锁,即两个或更多个线程等待释放同一对象。出于一样的缘由,锁定公共数据类型(相比于对象)也可能致使问题。并且lock(this)只对当前对象有效,若是多个对象之间就达不到同步的效果。lock(typeof(Class))与锁定字符串同样,锁定的对象的做用域的范围太广了。
3.1 使用Monitor类实现线程同步
Lock关键字是Monitor的一种替换用法,lock在IL代码中会被翻译成Monitor.
lock(obj)
{
//代码段
}
就等同于
Monitor.Enter(obj);
//代码段
Monitor.Exit(obj);
Monitor的经常使用属性和方法:
Enter(Object) 在指定对象上获取排他锁。
Exit(Object) 释放指定对象上的排他锁。
Pulse 通知等待队列中的线程锁定对象状态的更改。
PulseAll 通知全部的等待线程对象状态的更改。
TryEnter(Object) 试图获取指定对象的排他锁。
TryEnter(Object, Boolean) 尝试获取指定对象上的排他锁,并自动设置一个值,指示是否获得了该锁。
Wait(Object) 释放对象上的锁并阻止当前线程,直到它从新获取该锁。
经常使用的方法有两个,Monitor.Enter(object)方法是获取锁,Monitor.Exit(object)方法是释放锁,这就是Monitor最经常使用的两个方法,在使用过程当中为了不获取锁以后由于异常,致锁没法释放,因此须要在try{} catch(){}以后的finally{}结构体中释放锁(Monitor.Exit())。
Enter(Object)的用法很简单,看代码
static void Main(string[] args) { Thread threadA = new Thread(ThreadMethod); //执行的必须是无返回值的方法 threadA.Name = "A"; Thread threadB = new Thread(ThreadMethod); //执行的必须是无返回值的方法 threadB.Name = "B"; threadA.Start(); threadB.Start(); Thread.CurrentThread.Name = "C"; ThreadMethod(); Console.ReadKey(); } static object obj = new object(); public static void ThreadMethod() { Monitor.Enter(obj); //Monitor.Enter(obj) 锁定对象 try { for (int i = 0; i < 500; i++) { Console.Write(Thread.CurrentThread.Name); } } catch(Exception ex){ } finally { Monitor.Exit(obj); //释放对象 } }
3.2 mutex 互斥锁
四、线程池
上面介绍了介绍了平时用到的大多数的多线程的例子,但在实际开发中使用的线程每每是大量的和更为复杂的,这时,每次都建立线程、启动线程。从性能上来说,这样作并不理想(由于每使用一个线程就要建立一个,须要占用系统开销);从操做上来说,每次都要启动,比较麻烦。为此引入的线程池的概念。
好处:
1.减小在建立和销毁线程上所花的时间以及系统资源的开销
2.如不使用线程池,有可能形成系统建立大量线程而致使消耗完系统内存以及”过分切换”。
在什么状况下使用线程池?
1.单个任务处理的时间比较短
2.须要处理的任务的数量大
线程池最多管理线程数量=“处理器数 * 250”。也就是说,若是您的机器为2个2核CPU,那么CLR线程池的容量默认上限即是1000
经过线程池建立的线程默认为后台线程,优先级默认为Normal。