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);}}}

转载于:https://www.cnblogs.com/bile/p/6114506.html

c# 变量,对象,静态类型,集合类的线程安全回顾相关推荐

  1. 第四章 对象的类型和动态绑定

    动态绑定:程序在执行时才确定对象的属性和需要响应的信息. 多态:指同一操作作用于不同的类的实例时,将产生不同的执行结果.多态是面向对象的一个重要的特征,大大增强了软件的灵活性和扩展性. 把类作为类型去 ...

  2. 编程语言 - 强弱/动静态类型 - 整理

    1.应用场景 了解编程语言的分类及显著的区别, 帮助理解编程语言的本质,和帮助快速学习一门新的语言. 2.学习/操作 1. 文档阅读 12 | 栈空间和堆空间:数据是如何存储的?-极客时间 2. 整理 ...

  3. C++静态类型成员变量的初始化顺序(单例模式)

    对编译器来说,静态成员变量的初始化顺序和析构顺序是一个未定义的行为 #include <string> #include <iostream> using namespace ...

  4. 在python中类型属于对象变量是没有类型的_如何理解python对象有类型,变量无类型...

    在Python中,有这样一句话是非常重要的:对象有类型,变量无类型.怎么理解呢? 首先,5.6都是整数,Python中为它们取了一个名字,叫做"整数"类型的对象(或者数据),也可以 ...

  5. Python学习01、计算机基础概念、初识Python、常量,变量,类型和表达式、字符串、动态静态类型、注释

    前言:本文章主要用于个人复习,追求简洁,感谢大家的参考.交流和搬运,后续可能会继续修改和完善. 因为是个人复习,会有部分压缩和省略. 计算机基础概念 什么是计算机? 现在我们所说的计算机不光能进行算术 ...

  6. servlet单实例多线程 ---线程安全问题是由实例变量造成的,只要在Servlet里面的任何方法里面都不使用实例变量,那么该Servlet就是线程安全的。(所有建议不要在servlet中定义成员变

    Servlet 单例多线程 Servlet如何处理多个请求访问? Servlet容器默认是采用单实例多线程的方式处理多个请求的: 1.当web服务器启动的时候(或客户端发送请求到服务器时),Servl ...

  7. java中静态变量,静态代码块,静态方法,实例变量,匿名代码块的加载顺序

    1. java中静态变量,静态代码块,静态方法,实例变量,匿名代码块 在Java中,使用{}括起来的代码称为代码块,代码块可以分为以下四种: (1)普通代码块:就是类中方法的方法体 public vo ...

  8. Java中合理使用局部变量替代成员变量、静态变量

    故事起因 一个Java类中可以存在多种形式的变量,可以是最一般的成员变量.或静态变量.或临时变量.如下图: public class VariableDemo {static int staticVa ...

  9. Linux——线程同步(条件变量、POSIX信号量)和线程池

    一.线程同步 (一).概念 线程同步是一种多线程关系,指的是线程之间按照特定顺序访问临界资源,进而能够避免线程饥饿问题. 所谓线程饥饿指的是某个线程长期"霸占"临界资源,导致其他线 ...

最新文章

  1. IT 学习资料 大全
  2. C++中的union(联合体,共用体,数据变量可以共享内存,以节省内存空间)
  3. TCL系列 - incr命令
  4. 时间序列预测之二:灰色模型
  5. memcpy和strcpy的区别及memcmp和strcmp的区别
  6. 大数据Notebook调研信息汇总(持续更新中)
  7. 在生产环境下处理EFCore数据库迁移的五种方法
  8. python的六大数据类型中可以改变_在python中更改数组的数据类型
  9. python3.6程序_python3.6如何生成exe程序
  10. [转载] Java——数组习题
  11. 中移4G模块-ML302-OpenCpu开发-GPIO
  12. STM32编码器的学习笔记
  13. C# 根据url获取文件流流
  14. 人工智能这把双刃剑的利指的是什么?
  15. 计算机简谱转五线谱乐谱,五线谱如何转成简谱-五线谱转简谱图文教程 - Iefans...
  16. MySQL 两个数据库表中合并数据
  17. .NET Framework 4 安装未成功 一般信任关系失败
  18. CCF-卖菜(Python)
  19. d3.js-V3制作简单的飞线图
  20. 开源免费3D CAD软件:FreeCAD

热门文章

  1. Java中实现使用split方法分隔字符串
  2. 怎样在项目中使用git以及github管理(图文详解流程讲解)
  3. Kotlin 与 Java有什么区别(最全最新的)
  4. 2、mybatis主配置文件之properties
  5. html引入jquery_jQuery介绍
  6. 极简数据分析实操指南(下)
  7. 混沌大学签约神策数据,加快颠覆式创新教学步伐
  8. css元素居中方法归纳
  9. 解决Linux系统没有/etc/sysconfig/iptables文件
  10. Java中对象的深克隆和浅克隆