还是上一次,面试的时候提到了C#线程安全的问题,当时回答的记不太清了,大概就是多线程同是调用某一个函数时可能会照成数据发生混乱,运行到最后发现产生的结果或数据并不是自己想要的,或是跨线程调用属性或方法,即在一个线程中调用另一个线程中的数据,程序会提醒异常(当然这种问题的解决方法有好几种,这里不重点介绍)。

在这里详细总结了关于线程安全的一些问题,希望对大家有点帮助,如有错误的地方欢迎指出

1.线程安全:

如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。
或者说:一个类或者程序所提供的接口对于线程来说是原子操作或者多个线程之间的切换不会导致该接口的执行结果存在二义性,也就是说我们不用考虑同步的问题。
线程安全问题都是由全局变量及静态标量引起的。
若每个线程中对全局变量、静态变量只有读操作,而无写操作,一般来说,这个全局变量是线程安全的;若有多个线程同时执行写操作,一般都需要考虑线程同步,否则的话就可能影响线程安全。
2.线程不安全:

举例 比如一个 ArrayList 类,在添加一个元素的时候,它可能会有两步来完成:1. 在 Items[Size] 的位置存放此元素;2. 增大 Size 的值。

在单线程运行的情况下,如果 Size = 0,添加一个元素后,此元素在位置 0,而且 Size=1; 而如果是在多线程情况下,比如有两个线程,线程 A 先将元素存放在位置 0。但是此时 CPU 调度线程A暂停,线程 B 得到运行的机会。线程B也向此 ArrayList 添加元素,因为此时 Size 仍然等于 0 (注意哦,我们假设的是添加一个元素是要两个步骤哦,而线程A仅仅完成了步骤1),所以线程B也将元素存放在位置0。然后线程A和线程B都继续运行,都增加 Size 的值。 那好,现在我们来看看 ArrayList 的情况,元素实际上只有一个,存放在位置 0,而 Size 却等于 2。这就是“线程不安全”了。

3.解决线程安全的几种方法:

当需要在线程之间数据传递时,要解决线程安全只要注意同步和互斥操作就好。工作线程处理中可能想操作某个主线程的Windows Form的Control,比如按钮,ListView等等更新工作状态之类,直接控制是不行的,不能够跨线程操作另一个线程创建的Windows Form控件。要使用委托去调用。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Threading;namespace JPGCompact
{public partial class MainForm : Form{// 定义委托private delegate void DelegateWriteResult(string file, bool result);// 与定义的委托签名相同的函数,操作主线程控件private void WriteResult(string fileName, bool result){if (result){ListViewItem thisListItem = new ListViewItem();thisListItem.ForeColor = Color.White;thisListItem.BackColor = Color.DarkGreen;thisListItem.SubItems[0].Text = fileName;thisListItem.SubItems.Add("成功");lvResultList.Items.Add(thisListItem);}else{ListViewItem thisListItem = new ListViewItem();thisListItem.ForeColor = Color.White;thisListItem.BackColor = Color.Red;thisListItem.SubItems[0].Text = fileName;thisListItem.SubItems.Add("失败");lvResultList.Items.Add(thisListItem);}}// 启动线程private void btnStart_Click(object sender, EventArgs e){Thread workThread = new Thread(new ThreadStart(CompressAll));// 设置为背景线程,主线程一旦推出,该线程也不等待而立即结束workThread.IsBackground = true;workThread.Start();}// 线程执行函数private void CompressAll(){// 判断是否需要Invoke,多线程时需要if (this.InvokeRequired){// 通过委托调用写主线程控件的程序,传递参数放在object数组中this.Invoke(new DelegateWriteResult(WriteResult),new object[] { item, true });}else{// 如果不需要委托调用,则直接调用this.WriteResult(item, true);}}}
}

C#多线程、跨线程与线程安全的示例详解(三种不同方法)

using System.Threading;public static class Extensions{//控件扩展方法(用于跨线程操作),因为为了线程的安全,防止资源竞争出现死锁或不一致的状态,.NET是不允许进行跨线程访问窗体控件的。public static void SafeCall(this Control ctrl, Action callback){if (ctrl.InvokeRequired){ctrl.Invoke(callback);}else{callback();}}}public partial class Form1 : Form{public Form1(){InitializeComponent();CheckForIllegalCrossThreadCalls = false;//方法二(禁用异常,不检查跨线程调用的安全问题,可以自由拖动窗体,不过在严格条件下也不可取,数据可能不一致)//方法三(推荐使用)//把你要保护起来的代码作为一个回调,然后任何需要保护一些代码的地方都可以这样调用ThreadPool.QueueUserWorkItem(h =>{int i = 0;while (true){//如果没有SafeCall方法,将出现“线程间操作无效: 从不是创建控件“textBox1”的线程访问它。”的错误匿名委托//textBox1.SafeCall(delegate()//{//    textBox1.Text = (i++).ToString();//});//Lambda表达式textBox1.SafeCall(() =>{textBox1.Text = (i++).ToString();});//Thread.Sleep(100);}});}//抽奖示例public bool flag = true;public void choujiang(){flag = true;while (flag){Random rnd = new Random();textBox1.Text = rnd.Next(1, 100).ToString();//Application.DoEvents();//方法一:这样也可以防止UI界面线程的阻塞,不至于被卡死。但是在拖动界面或其他操作的时候,程序会被暂停}}//开始private void button1_Click(object sender, EventArgs e){//choujiang();//方法一new Action(choujiang).BeginInvoke(null, null);//方法二}//暂停private void button2_Click(object sender, EventArgs e){flag = false;}}

注:本文章属个人学习总结,部分内容参考互联网上的相关文章。 其中如果发现个人总结有不正确的认知或遗漏的地方请评论告知,欢迎交流。

C#线程安全的那些事相关推荐

  1. 线程与线程池的那些事之线程篇

    本文关键字: 线程,线程池,单线程,多线程,线程池的好处,线程回收,创建方式,核心参数,底层机制,拒绝策略,参数设置,动态监控,线程隔离 线程和线程池相关的知识,是Java学习或者面试中一定会遇到的知 ...

  2. for循环里面有异步操作_JS 线程与异步的那些事

    已知,JavaScript 是单线程的,天生异步,适合 IO 密集型,不适合 CPU 密集型,但是,为什么是异步的喃,异步由何而来的喃,我们将在这里逐渐讨论实现. 一.进程与线程 1. 浏览器是多进程 ...

  3. Android Kotlin okhttp Retrofit 线程协程那些事

    这篇文章不是用来讲概念的, 只是用来谈论一些关于Android 进程\协程那些问题 1. android 子线程中的异常会引发crash闪退吗? 答案是会的 Thread{throw RuntimeE ...

  4. 一篇就够,线程与线程池的那些事之线程池篇

    本文关键字: 线程 , 线程池 , 单线程 , 多线程 , 线程池的好处 , 线程回收 , 创建方式, 核心参数 , 底层机制 , 拒绝策略 , 参数设置 , 动态监控 , 线程隔离 线程和线程池相关 ...

  5. java 线程不足_Java 线程基础知识

    wait() 和notify().notifyAll() 这三个方法用于协调多个线程对共享数据的存取,所以必须在 Synchronized 语句块内使用这三个方法,否则会抛出错 IllegalMoni ...

  6. Java 线程池相关问题

    线程池的拒绝策略 AbortPolicy:直接抛出异常阻止系统正常工作. CallerRunsPolicy:只要线程池未关闭,该策略直接在调用者线程中,运行当前被丢弃的任务. DiscardOldes ...

  7. Java面试题:线程实现的两种方式及匿名内部类实现

    QUESTION:线程实现的两种方式及匿名内部类实现 ANSWER: 1.多线程两种实现方式 (1)继承Thread     * 定义类继承Thread     * 重写run方法     * 把新线 ...

  8. JAVA:线程总结及多线程实现的两种方法

    JAVA:线程总结 目录 目录 JAVA:线程总结 JAVA:线程总结 01_多线程(多线程的引入)(了解) 02_多线程(多线程并行和并发的区别)(了解) 03_多线程(Java程序运行原理和JVM ...

  9. 并发、并行、线程、进程与CPU基本概念

    转载自: https://blog.csdn.net/qq_21480607/article/details/100135524 首先我们需要了解一些基础概念: 串行,并发与并行 串行 多个任务,执行 ...

最新文章

  1. 写一个函数days,实现计算本年第几天
  2. python图像直方图与直方图均衡化
  3. 【若依(ruoyi)】Bootstrap-Table的使用
  4. Python、Perl 垫底,C语言才是最环保的编程语言
  5. 理解 Linux 中 `ls` 的输出
  6. 蓝桥杯 2017 国赛B组C/C++【对局匹配】
  7. Visual Web Developer 中的网站类型
  8. django girls_Django Girls Budapest团队的活动筹划技巧
  9. unity 主线程调用_Kafka的Producer的调用序列图
  10. 学习了pr后的收获_零基础如何学习PR影视剪辑以及调色?
  11. 存储设备在linux名称,Linux下的存储设备的管理
  12. 软件工程:状态,行为,事件
  13. 微信小程序调用域名服务器的服务
  14. 雷军的博客分享- 这局棋,我站在人工智能这边
  15. 计算机恢复语言文件格式,txt文件乱码怎么恢复正常
  16. STM32超低功耗入门之认识超低功耗
  17. Hdu1329Hanoi Tower Troubles Again!
  18. 【自然语言处理概述】文本词频分析
  19. linux检查网络是否通畅_Linux检测网络通畅命令
  20. 网格顶点法向量从世界坐标到切空间坐标转换:法向贴图高低模烘焙

热门文章

  1. Qt Designer的信号和插槽编辑模式
  2. Qt Creator IDE概述
  3. OpenGL 着色器的N体仿真
  4. mes系统服务器要求,mes系统 服务器配置
  5. map的生命周期 java,【JAVA面试的艺术】JAVA基础知识阶段三
  6. python求两数最大公因数_『用python求俩个数的最大公约数和最小公倍数』
  7. java分页模板_java 分页模型的模板
  8. 02_创建Git仓库,克隆仓库,git add,git commit,git push,git pull,同行冲突,不同行冲突的结局方案,git mergetool的使用
  9. JavaScript中window对象属性,时间等的总结
  10. FreeMarker语法指南