同步

  当多个线程共享一些数据的时候,我们就需要使用同步技术,确保一次只有一个线程访问合改变共享状态。注意,同步问题与争用和死锁有关。

例:

static int idx = ;
static void Add()
{
for (int i = ; i < ; i++)
{
idx++;
}
}
static void Main()
{
const int SIZE = ;
Task[] arr = new Task[SIZE];
while (true)
{
for (int i = ; i < SIZE; i++)
{
arr[i] = new Task(Add);
arr[i].Start(); //启动多个线程
} for (int i = ; i < SIZE; i++)
{
arr[i].Wait(); //等待线程完成
} Console.WriteLine(idx);
Thread.Sleep();
idx = ;// 重置数据,再次运行
}
}

结果:

1717634
1652989
1444839
1272385
1558097
1297459
1968232
2000000

显然,不是我们想要的,我们期望每次运行的结果都是2000000。这是因为idx++不是线程安全的,它的操作包括从内存中获取一个值,给该值递增1,再将它存回内存。这些操作都可能会被线程调度器打断。

这种情况下,我们就需要一些同步方法解决该问题。

  • lock关键字将语句块标记为临界区,方法是获取给定对象的互斥锁,执行语句,然后释放该锁。在块的开始处调用 Enter,而在块的结尾处调用 Exit。这样可确保当一个线程位于代码的关键部分时,另一个线程不会进入该关键部分。 如果其他线程尝试进入锁定的代码,则它将一直等待(即被阻止),直到该对象被释放。一个线程,当阻塞的时候,不占用CPU资源。
static object locker = new object();
static void Add()
{
for (int i = ; i < ; i++)
{
lock (locker)
idx++;
}
}
  • Interlocked类用于使变量的简单语句原子话(最小执行单元,不会被中途打断),提供了以线程安全的方式递增、递减、交换和读取值的方法。
对上例而言,把idx++替换成Interlocked.Increment(ref idx);
  • Monitor类算是实现锁机制的纯正类,lock语句由编译器解析为使用Monitor类。
lock(obj)
{
//synchronized region for obj
} 相当于 Monitor.Enter(obj);
try
{
//synchornized region for obj
}
finally
{
Monitor.Exit(obj)
}

用TryEnter可以添加timeout

 object obj = new object();
Task.Run(()=>{
lock(obj)
{
Console.WriteLine("lock obj");
Thread.Sleep();
}
});
bool b = Monitor.TryEnter(obj, );
if (b)
{
try
{
Console.WriteLine("monitor enter.");
}
finally
{
Monitor.Exit(obj);
}
}
else
{
Console.WriteLine("monitor enter false.");
} Console.ReadKey();

另外,Monitor还提供了Wait方法,用于释放对象上的锁并阻止当前线程,直到它重新获取该锁。

提供了Pulse方法用于通知等待队列中的线程锁定对象状态的更改;PulseAll通知所有的等待线程对象状态的更改。

  •  SpinLock自旋锁,如果基于对象锁定(Monitor)的系统开销由于垃圾回收而过高,就可以使用SpinLock结构。如果有大量的锁定(例如,列表中的每个节点都有一个锁定),且锁定的时间总是非常短,SpinLock结构就很有用。应避免使用多个SpinLock结构,也不要调用任何可能阻塞的内容。SpinLock 应仅用于您,这样做可以改进应用程序的性能确定后。 还有一点需要注意 SpinLock 是值类型,为了提高性能。 出于此原因,您必须非常小心,以免意外复制 SpinLock 实例,因为两个实例 (原始项和副本) 都将完全相互独立的这可能会导致错误行为的应用程序。 如果 SpinLock 必须围绕传递实例,则应通过引用而不是通过值传递。

    请不要在存储 SpinLock 只读字段中的实例。

最新文章

  1. JavaScript之单例实战
  2. 《DSP using MATLAB》示例Example5.20
  3. SQL Server Reporting Service(SSRS) 第二篇 SSRS数据分组Parent Group
  4. spring访问静态资源出错,No mapping found for HTTP request with URI xxx/resources/js/jquery.min.js...
  5. Loadrunner11.0 录制手机App脚本的方法
  6. Setup Apache + PHP + MySql on Windows 10
  7. hdu4291之矩阵快速幂
  8. 深入浅出ExtJS 第二章 Ext框架基础
  9. android之模拟器更新底层
  10. 在CentOS6.0上安装Oracle 11gR2 (11.2.0.1)以及基本的配置(一)
  11. jQeury学习笔记
  12. ThinkPHP - 每个操作都检测用户是否登录
  13. Quartz(GUI)图形界面程序----Quartz Web
  14. MySQL GTIDs(global transaction identifiers)
  15. 微信小程序换皮肤,动态切换菜单栏和导航栏的样式,动态修改TabBar和NavigationBar
  16. ubuntu中minicom安装和使用
  17. JS读取.properties文件的方法
  18. linux --- 1.初始linux
  19. 抠图|计蒜客2019蓝桥杯省赛 B 组模拟赛(一)
  20. DB2与Sybase/Oracle/Informix的比较

热门文章

  1. 二、第一个ECharts图表
  2. 【Codeforces 264B】Good Sequences
  3. SGU -1500 - Pass Licenses
  4. Sql语句中关于如何在like &#39;%?%&#39;中给?赋值
  5. Just a Hook 线段树 区间更新
  6. kendo grid 点击新增没有反映
  7. mysql MVCC原理理解
  8. com.101tec.ZKClient实现中的subscribeDataChanges设置的监听器事件不回调的问题研究
  9. java中POJO类和DTO类都要实现序列化
  10. Workflow:添加工作流存储功能