c# 变量,对象,静态类型,集合类的线程安全回顾
1.变量的线程安全性与变量的作用域有关。
2.对象
对象是类型的实例
在创建对象时,会单独有内存区域存储对象的属性和方法。所以,一个类型的多个实例,在执行时,只要没有静态变量的参与,应该都是线程安全的。
这跟我们调试状态下,是不一样的。调试状态下,如果多个线程都创建某实例的对象,每个对象都调用自身方法,在调试是,会发现是访问的同一个代码,多个线程是有冲突的。但是,真正的运行环境是线程安全的。
以销售员为例,假设产品是充足的,多个销售员,销售产品,调用方法:Sale(),其是线程安全的。
但是,如果涉及到仓库,必须仓库有足够的产品才能进行销售,这时,多个销售人员就有了临界资源:仓库。
在这里我们只讨论对象的普通方法。至于方法传入的参数,以及方法内对静态变量操作的,这里需要根据参数和静态变量来判定方法的线程安全性。
销售员案例:

- using System;
- using System.Threading;
- namespace MutiThreadSample.Sale
- {
- /// <summary>
- /// 销售
- /// </summary>
- public class Saler
- {
- /// <summary>
- /// 名称
- /// </summary>
- public string Name { get; set; }
- /// <summary>
- /// 间隔时间
- /// </summary>
- public int IntervalTime { get; set; }
- /// <summary>
- /// 单位时间销售运量
- /// </summary>
- public int SaleAmount { get; set; }
- /// <summary>
- /// 销售
- /// </summary>
- public void Sale()
- {
- Console.WriteLine("销售:{0} 于 {1} 销售产品 {2}", this.Name, DateTime.Now.Millisecond, this.SaleAmount);
- Thread.Sleep(IntervalTime);
- }
- /// <summary>
- /// 销售
- /// </summary>
- /// <param name="interval">时间间隔</param>
- public void Sale(object obj)
- {
- WHouseThreadParameter parameter = obj as WHouseThreadParameter;
- if (parameter != null)
- {
- while (parameter.WHouse != null && parameter.WHouse.CanOut(this.SaleAmount))
- {
- parameter.WHouse.Outgoing(this.SaleAmount);
- Console.WriteLine("Thread{0}, 销售:{1} 于 {2} 销售出库产品 {3}", Thread.CurrentThread.Name, this.Name, DateTime.Now.Millisecond, this.SaleAmount);
- Thread.Sleep(this.IntervalTime);
- }
- }
- }
- }
- }

3静态类型
已经讲了类的实例--对象的多线程安全性问题。这里只讨论类型的静态变量和静态方法。
当静态类被访问的时候,CLR会调用类的静态构造器(类型构造器),创建静态类的类型对象,CLR希望确保每个应用程序域内只执行一次类型构造器,为了做到这一点,在调用类型构造器时,CLR会为静态类加一个互斥的线程同步锁,因此,如果多个线程试图同时调用某个类型的静态构造器时,那么只有一个线程可以获得对静态类的访问权,其他的线程都被阻塞。第一个线程执行完 类型构造器的代码并释放构造器之后,其他阻塞的线程被唤醒,然后发现构造器被执行过,因此,这些线程不再执行构造器,只是从构造器简单的返回。如果再一次调用这些方法,CLR就会意识到类型构造器被执行过,从而不会在被调用。
调用类中的静态方法,或者访问类中的静态成员变量,过程同上,所以说静态类是线程安全的。
最简单的例子,就是数据库操作帮助类。这个类的方法和属性是线程安全的。

- using System;
- namespace MutiThreadSample.Static
- {
- public class SqlHelper
- {
- /// <summary>
- /// 数据库连接
- /// </summary>
- private static readonly string ConnectionString = "";
- /// <summary>
- /// 执行数据库命令
- /// </summary>
- /// <param name="sql">SQL语句</param>
- public static void ExcuteNonQuery(string sql)
- {
- //执行数据操作,比如新增、编辑、删除
- }
- }
- }

但是,对于静态变量其线程安全性是相对的,如果多个线程来修改静态变量,这就不一定是线程安全的。而静态方法的线程安全性,直接跟传入的参数有关。
总之:
针对变量、对象、类型,说线程安全性,比较笼统,在这里,主要是想让大家明白,哪些地方需要注意线程安全性。对于变量、对象(属性、方法)、静态变量、静态方法,其线程安全性是相对的,需要根据实际情况而定。
万剑不离其宗,其判定标准:是否有临界资源。
4、集合类型是线程安全的吗?
常用的集合类型有List、Dictionary、HashTable、HashMap等。在编码中,集合应用很广泛中,常用集合来自定义Cache,这时候必须考虑线程同步问题。
默认情况下集合不是线程安全的。在System.Collections 命名空间中只有几个类提供Synchronize方法,该方法能够超越集合创建线程安全包装。但是,System.Collections命名空间中的所有类都提供SyncRoot属性,可供派生类创建自己的线程安全包装。还提供了IsSynchronized属性以确定集合是否是线程安全的。但是ICollection泛型接口中不提供同步功能,非泛型接口支持这个功能。
Dictionary(MSDN解释)
此类型的公共静态(在 Visual Basic 中为 Shared)成员是线程安全的。 但不保证所有实例成员都是线程安全的。
只要不修改该集合,Dictionary<TKey, TValue> 就可以同时支持多个阅读器。 即便如此,从头到尾对一个集合进行枚举本质上并不是一个线程安全的过程。 当出现枚举与写访问互相争用这种极少发生的情况时,必须在整个枚举过程中锁定集合。 若允许多个线程对集合执行读写操作,您必须实现自己的同步。
很多集合类型都和Dictionary类似。默认情况下是线程不安全的。当然微软也提供了线程安全的Hashtable.
HashTable
Hashtable 是线程安全的,可由多个读取器线程和一个写入线程使用。 多线程使用时,如果只有一个线程执行写入(更新)操作,则它是线程安全的,从而允许进行无锁定的读取(若编写器序列化为 Hashtable)。 若要支持多个编写器,如果没有任何线程在读取 Hashtable 对象,则对 Hashtable 的所有操作都必须通过 Synchronized 方法返回的包装完成。
从头到尾对一个集合进行枚举本质上并不是一个线程安全的过程。 即使某个集合已同步,其他线程仍可以修改该集合,这会导致枚举数引发异常。 若要在枚举过程中保证线程安全,可以在整个枚举过程中锁定集合,或者捕捉由于其他线程进行的更改而引发的异常。
线程安全起见请使用以下方法声明
- /// <summary>
- /// Syncronized方法用来创造一个新的对象的线程安全包装
- /// </summary>
- private Hashtable hashtable = Hashtable.Synchronized(new Hashtable());
在枚举读取时,加lock,这里lock其同步对象SyncRoot

- /// <summary>
- /// 读取
- /// </summary>
- public void Read()
- {
- lock(hashtable.SyncRoot)
- {
- foreach (var item in hashtable.Keys)
- {
- Console.WriteLine("Key:{0}",item);
- }
- }
- }

c# 变量,对象,静态类型,集合类的线程安全回顾的更多相关文章
- C++静态变量对象的建立和删除,兼论MFC开始运行的起点(全局对象)
看了不少C++书,当讲到静态变量的时候,总是以int成员来举例,是啊,这样很好理解.但是如果这个静态变量是一个对象行不行呢?不仅行,有时候还非常必要,而且别有洞天. 比如: // .h 文件 clas ...
- 【转载】C#使用typeof运算符获取对象变量的具体类型Type
在C#的实际类型操作过程中,有时候需要通过typeof方法获取对象的类型对应的Type变量即具体类型,例如在获取DataTable中某一列的具体数据类型的时候,我们就会用到typeof方法来获取具体的 ...
- JVM存储位置分配——java中局部变量、实例变量和静态变量在方法区、栈内存、堆内存中的分配
Java中的变量根据不同的标准可以分为两类,以其引用的数据类型的不同来划分可分为“原始数据类型变量和引用数据类型变量”,以其作用范围的不同来区分可分为“局部变量,实例变量和静态变量”. 根据“Java ...
- Java中局部变量、实例变量和静态变量在方法区、栈内存、堆内存中的分配
转自:https://blog.csdn.net/leunging/article/details/80599282 感谢CSDN博主「leunging」的总结分享 ———————————————— ...
- 第40天学习打卡(静态代理 Lambda表达式 线程状态 线程同步 同步方法)
静态代理 package com.kuang.demo03; //静态代理模式总结 //真实对象和代理对象都要实现同一个接口 //代理对象要代理真实角色 //好处: //代理对象可以做很多真实对象 ...
- C++从静态类型到单例模式
目录 1. 概述 2. 详论 2.1. 静态类型 2.1.1. 静态方法成员 2.1.2. 静态数据成员 2.2. 单例模式 2.2.1. 实现 2.2.2. 问题 3. 参考 1. 概述 很多的知识 ...
- 把《c++ primer》读薄(1-2前言+变量和基本类型)
督促读书,总结精华,提炼笔记,抛砖引玉,有不合适的地方,欢迎留言指正. 一:大小端的概念 Big-Endian和Little-Endian(见计算机存储的大小端模式解析) 二:浮点数的机器级表示 (见 ...
- C++ Primer 变量和基本类型
<C++ Primer 4th>读书摘要 基本上所有的语言都要提供下列特征: • 内置数据类型,如整型.字符型等. • 表达式和语句:表达式和语句用于操纵上述类型的值. • 变量:程序员可 ...
- 高性能PHP支持静态类型
PHP+QB是一个可选的PHP虚拟机,它声称在性能上提供了数量级的提升.而负面影响就是它需要所有的内容都必须是静态类型,同时也对数组做了一些限制. 静态 类型声明 是通过PHPDoc语法的一个扩展添加 ...
随机推荐
- Android 媒体存储服务(二)
Android 媒体存储服务 简介: 本文是<深入Android媒体存储服务>系列第二篇,简要介绍媒体存储服务扫描文件的流程.文中介绍的是 Android 4.2. Android 有一套 ...
- mmzb游戏事故分析
最近一次线上更新,老项目挂了,遍地哀嚎,日活跃掉了好多,心痛... 这次维护时,SA为了缩减硬件资源,做了一次数据库迁移.给到开发手上的player db,只有一些索引数据,不带有任一玩家数据.玩家上 ...
- Some thing about Graph
Learning CNNs for Arbitrary Graphs (Graph-like data): Learning Convolutional Neural Networks for Gra ...
- folly::AtomicHashmap源码分析(一)
本文为原创,转载请注明:http://www.cnblogs.com/gistao/ Atomic的两点背景 看下这个场景,老张去厕所,发现门是锁着的,他就在门口等着里边人出来,此时小王也来了,他想了 ...
- Default Title
測試的標誌 代表意義 1. 關於某個檔名的『檔案類型』判斷,如 test -e filename 表示存在否 -e 該『檔名』是否存在?(常用) -f 該『檔名』是否存在且為檔案(file)?(常用) ...
- PHP character garbled
MySql 控制台查询时出现乱码 Database&Table 的字符集 于Mysql控制台显示的字符集不一样 右键单击mysql控制台边框 单击属性 查看当前代码页的字符集模式是否于数 ...
- Exynos 4412
Exynos 4412采用了三星最新的32nm HKMG工艺,是三星的第一款四核处理器 1.启动 有时间再接着写……
- 关于C#操作数据库ExecuteNonQuery()的返回值问题
) { retValue = AccessCon.ExecuteSql(sql = "update salesData set sellingPrize='" + man.Sell ...
- springMvc3.0.5搭建全程 (转)
用了大半年的Spring MVC3.0,用着感觉不错.简单写一个搭建Spring MVC3.0的流程(以Spring3.0.5为列),数据库交互使用spring JDBC Template,附件有项目 ...
- [llvm] Call the LLVM Jit from c program
stackoverflow: http://stackoverflow.com/questions/1838304/call-the-llvm-jit-from-c-program Another t ...