C#的线程安全类为何还是得加 lock ?

问题描述

publicvoidParallelBreak(){Console.WriteLine("n—————{0}—————",MethodBase.GetCurrentMethod().Name);ConcurrentBag<int>bag=newConcurrentBag<int>();stopWatch.Start();Parallel.For(0,1000,(i,state)=>{//此处加lock(bag)则输出一定是300.否则不一定是300,可能是302,300,306等if(bag.Count>=300){state.Stop();return;}bag.Add(i);});stopWatch.Stop();Console.WriteLine("Bagcountis"+bag.Count+","+stopWatch.ElapsedMilliseconds);}

以上代码,输出为:不太明白,既然是线程安全类,为什么不加lock就不能保证输出为300呢?

解决方案

解决方案二:
bag.Count>=300的判断和bag.Add两者不是原子操作。可能两个线程都判断bag.Count=299,然后各自插入一个,虽然读取、插入是线程安全的,但是不能保证结果是300
解决方案三:
引用1楼caozhy的回复:

bag.Count>=300的判断和bag.Add两者不是原子操作。可能两个线程都判断bag.Count=299,然后各自插入一个,虽然读取、插入是线程安全的,但是不能保证结果是300

多谢版主,还提一个问题:下面的这段代码,大多数情况是可以运行的,但有时又会报下图的错误,是什么原因呢?publicstaticvoidListWithParallel(){Console.WriteLine("—————{0}—————",MethodBase.GetCurrentMethod().Name);List<int>list=newList<int>();Parallel.For(0,10000,item=>{list.Add(item);});Console.WriteLine("List'scountis{0}",list.Count());}

解决方案四:
线程安全的意思就是多线程做某个操作结果和你预期的是一样的List不是线程安全的,同时添加数据自然会出问题如果你要刨根问底,为什么会出这个错,不妨看下List.Capcity的代码
解决方案五:
线程安全跟加不加lock没有关系。所谓线程安全,是说它的任何在单线程上安全的操作在瞬间并发时也不会抛出逻辑出错。例如一个线程读取list[2]单元,另一个线程也读取list[2]单元,在逻辑上不会抛出异常!只要一个操作在瞬间并发时并不会出现逻辑错误,这就是线程安全的。再比如说一个线程执行list.Move(n),另一个线程也执行list.Move(n),或许结果是对的(例如删除了某个对象)也可能是错误(例如把紧挨在一起的两个对象都删除了),但是不会报错,这就说明它是安全的。比如说一个线程为list增加了一个单元,并不会影响另外一个线程读取list.Count,这就是说明它是线程安全的。线程安全的,并不代表着“先后次序的不同操作”不需要考虑逻辑出错问题。线程安全的东西,实际上一点也没有保证数据不会混乱!!!你在设计前后流程逻辑时照样要使用lock等等同步考虑,你不知道线程安全是在哪一个具体的点上“是安全的”,怎么就能随便“抠字眼儿”就说线程安全就不用lock了呢?线程安全的意思,是说技术数据混乱了,程序仍然不报错。这就好比如说你使用一个NoSql而可以随便并发修改数据(甚至混乱地修改数据),儿你并不会像传统的关系数据库一样收到“事务冲突、事务加锁超时”之类的异常。实际上,线程安全的,就意味着它很容易数据混乱,而并不会报错!所以仍然需要你亲自编代码用lock等语句来保证业务意义上的数据一致性。
解决方案六:
比如说一个国家它说“随便什么人都可以越境进入,根本不会因为偷渡而被捕”,于是你就说这个国家是“安全的”。请问这个国家的治安是安全的吗?你就是误会了“线程安全的”这个概念。线程安全的,并不意味着你要少一点点对lock等等数据安全的考虑。有些类不但是“线程安全的”,而且花费了巨大的时间和空间代码来做到了“私有化”,你认为的“安全”是那种东西低效率的安全吧?!
解决方案七:
很高兴能解答这个问题。其实您只要记住一句话就好:线程安全和数据同步是两码事儿。您的程序是线程安全的,不会出错(起码计算机是这么认为的)但他的数据是不同步的,因为你是并发运行,速度太快,计算机也不确定谁先谁后。所以你需要同步一下。就是LOCK起来。。C#有很多线程同步的类什么信号量互斥量锁自旋锁。看你需要选择合适的用。

时间: 2024-10-29 21:17:59

C#的线程安全类为何还是得加 lock ?的相关文章

基本线程同步(五)使用Lock同步代码块

声明:本文是< Java 7 Concurrency Cookbook >的第二章,作者: Javier Fernández González     译者:许巧辉 校对:方腾飞 使用Lock同步代码块 Java提供另外的机制用来同步代码块.它比synchronized关键字更加强大.灵活.它是基于Lock接口和实现它的类(如ReentrantLock).这种机制有如下优势: 它允许以一种更灵活的方式来构建synchronized块.使用synchronized关键字,你必须以结构化方式得到释

java.util.Random类是线程安全类吗?

问题描述 也即可以在多个线程下使用同同一个Random对象吗? 解决方案 解决方案二:该回复于2010-10-25 13:17:30被版主删除解决方案三:该回复于2010-10-25 13:17:31被版主删除解决方案四:该回复于2010-10-25 13:17:32被版主删除解决方案五:额,可以使用同一个对象,对类的对象有了更好的认识已学习解决方案六:楼主担心多条线程得到一个相同的随机数?Math.random()方法更易于使用,此方法是完全同步的,可允许多个线程使用而不出现错误.底层也是ne

Android使用线程池实现图片异步加载

http://keegan-lee.diandian.com/post/2012-12-14/40046198902 Android技术积累:图片缓存管理 http://keegan-lee.diandian.com/post/2012-12-06/40047548955

基于Boost的数据处理器及线程安全类和信号量

http://download.csdn.net/download/great3779/3998262

基本线程同步(七)修改Lock的公平性

修改Lock的公平性 在ReentrantLock类和 ReentrantReadWriteLock类的构造器中,允许一个名为fair的boolean类型参数,它允许你来控制这些类的行为.默认值为 false,这将启用非公平模式.在这个模式中,当有多个线程正在等待一把锁(ReentrantLock或者 ReentrantReadWriteLock),这个锁必须选择它们中间的一个来获得进入临界区,选择任意一个是没有任何标准的.true值将开启公平 模式.在这个模式中,当有多个线程正在等待一把锁(R

基本线程同步(八)在Lock中使用多个条件

在Lock中使用多个条件 一个锁可能伴随着多个条件.这些条件声明在Condition接口中. 这些条件的目的是允许线程拥有锁的控制并且检查条件是否为true,如果是false,那么线程将被阻塞,直到其他线程唤醒它们.Condition接口提供一种机制,阻塞一个线程和唤醒一个被阻塞的线程. 在并发编程中,生产者与消费者是经典的问题.我们有一个数据缓冲区,一个或多个数据生产者往缓冲区存储数据,一个或多个数据消费者从缓冲区中取出数据,正如在这一章中前面所解释的一样. 在这个指南中,你将学习如何通过使用

《Java并发编程实战》学习笔记 线程安全、共享对象和组合对象

第一章 介绍 线程的优势: 充分利用多处理器 简化模型 简化异步事件的处理 提供用户界面的响应(时间) 线程的风险: 安全的风险(不好的事情会发生),提高错误出现的几率 活性的风险(好的事情不会发生),如某些代码不会执行,出现死锁.活锁以及饥饿 性能的风险,不好的多线程编程可能会危害性能 第二章 线程安全 编写线程安全的代码,实质是管理对状态的访问,尤其是那些共享.可变的状态.对象的状态包括任何能影响它外部可见行为的数据. 当有过个线程能访问状态变量时,而且他们当中能对变量进行修改,则需要对他们

Java线程面试题 Top 50

不管你是新程序员还是老手,你一定在面试中遇到过有关线程的问题.Java语言一个重要的特点就是内置了对并发的支持,让Java大受企业和程序员 的欢迎.大多数待遇丰厚的Java开发职位都要求开发者精通多线程技术并且有丰富的Java程序开发.调试.优化经验,所以线程相关的问题在面试中经常会 被提到. 在典型的Java面试中, 面试官会从线程的基本概念问起, 如:为什么你需要使用线程, 如何创建线程,用什么方式创建线程比较好(比如:继承thread类还是调用Runnable接口),然后逐渐问到并发问题像

Java线程面试题 Top 50(转)

  不管你是新程序员还是老手,你一定在面试中遇到过有关线程的问题.Java语言一个重要的特点就是内置了对并发的支持,让Java大受企业和程序员的欢迎.大多数待遇丰厚的Java开发职位都要求开发者精通多线程技术并且有丰富的Java程序开发.调试.优化经验,所以线程相关的问题在面试中经常会被提到. 在典型的Java面试中, 面试官会从线程的基本概念问起, 如:为什么你需要使用线程, 如何创建线程,用什么方式创建线程比较好(比如:继承thread类还是调用Runnable接口),然后逐渐问到并发问题像