博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
线程安全与锁
阅读量:6435 次
发布时间:2019-06-23

本文共 3731 字,大约阅读时间需要 12 分钟。

线程安全

线程安全是多线程编程时的计算机程序代码中的一个概念。在拥有共享数据的多条线程并行执行的程序中,线程安全的代码会通过同步机制保证各个线程都可以正常且正确的执行,不会出现数据污染等意外情况。

多个线程访问同一个对象时,如果不用考虑这些线程在运行时环境下的调度和交替执行,也不需要进行额外的同步,或者在调用方进行任何其他操作,调用这个对象的行为都可以获得正确的结果,那么这个对象就是线程安全的。

线程安全问题往往都是由全局变量及静态变量引起的。

若每个线程中对全局变量、静态变量只有读操作,而无写操作,一般来说,这个全局变量是线程安全的;若有多个线程同时执行写操作,一般都需要考虑线程同步,否则的话就可能影响线程安全。

 

C#中的lock

在C#语言中,开发人员可以使用 lock 语句确保线程安全。lock 语句获取给定对象的互斥 lock,执行语句块,然后释放 lock。持有 lock 时,持有 lock 的线程可以再次获取并释放 lock。阻止任何其他线程获取 lock 并等待释放lock。在lock语句块中不能使用await关键字。语法如下。

lock (x){    // Your code...}

 

对实例内的共享变量,要实现该变量的同步线程访问,可以锁定专用的对象实例(private readonly object  balanceLock = new object())

Account 类,该类通过锁定专用的 balanceLock 实例来同步对其专用 balance 字段的访问。 使用相同的实例进行锁定可确保尝试同时调用 Debit 或 Credit 方法的两个线程无法同时更新 balance 字段。

using System;using System.Threading.Tasks;public class Account{    private readonly object balanceLock = new object();    private decimal balance;    public Account(decimal initialBalance)    {        balance = initialBalance;    }    public decimal Debit(decimal amount)    {        lock (balanceLock)        {            if (balance >= amount)            {                Console.WriteLine($"Balance before debit :{balance, 5}");                Console.WriteLine($"Amount to remove     :{amount, 5}");                balance = balance - amount;                Console.WriteLine($"Balance after debit  :{balance, 5}");                return amount;            }            else            {                return 0;            }        }    }    public void Credit(decimal amount)    {        lock (balanceLock)        {            Console.WriteLine($"Balance before credit:{balance, 5}");            Console.WriteLine($"Amount to add        :{amount, 5}");            balance = balance + amount;            Console.WriteLine($"Balance after credit :{balance, 5}");        }    }}class AccountTest{    static void Main()    {        var account = new Account(1000);        var tasks = new Task[100];        for (int i = 0; i < tasks.Length; i++)        {            tasks[i] = Task.Run(() => RandomlyUpdate(account));        }        Task.WaitAll(tasks);    }    static void RandomlyUpdate(Account account)    {        var rnd = new Random();        for (int i = 0; i < 10; i++)        {            var amount = rnd.Next(1, 100);            bool doCredit = rnd.NextDouble() < 0.5;            if (doCredit)            {                account.Credit(amount);            }            else            {                account.Debit(amount);            }        }    }}
View Code

private ,设为私有的以确保不被实例外部访问, 避免对不同的共享资源使用相同的 lock 对象实例,因为这可能导致死锁或锁争用。

readonly,确保balancLock对象不会被修改,若balancLock被修改,其他线程也会被放进来。

 

对某个类的多个实例之间的共享变量(资源),若要实现该变量(资源)的同步线程访问,可以锁定静态字段对象实例(private static  readonly object  writeLock = new object())

class Program    {        static void Main(string[] args)        {            List
logs = new List
(){
/*new10次*/ }; for(int i=0;i<10;i++) { Thread thread = new Thread(new ThreadStart(logs[i].wirteLog)); thread.Start(); } } } class Log { private static readonly object wirteLock = new object(); public void wirteLog() { lock (wirteLock) { FileInfo txt = new FileInfo("log.txt"); FileStream stream= txt.Open(FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.Read); byte[] buffer = Encoding.UTF8.GetBytes("xxx"); stream.Seek(stream.Length,SeekOrigin.Begin); stream.Write(buffer, 0, buffer.Length); stream.Close(); stream.Dispose(); } } }
View Code

 

 

参考引用

 

转载于:https://www.cnblogs.com/xurongjian/p/10216911.html

你可能感兴趣的文章
CentOS 7 配置IP
查看>>
文本处理工具grep及正则表达式
查看>>
Intel VT-x处于禁用状态
查看>>
用什么软件可以修改PDF文件,软件的操作方法
查看>>
如何精简企业主数据“裹脚布”
查看>>
& 号和管道符号(|)在不同场景下的使用方法
查看>>
curl 浏览器模拟请求实战
查看>>
多个VLAN中的vrrp备份组配置举例
查看>>
运维自动化之使用PHP+MYSQL+SHELL打造私有监控系统(六)
查看>>
interlib在tomcat7.0的安装
查看>>
水晶报表在大型WEB内部管理系统里的滑铁卢
查看>>
我的友情链接
查看>>
Git学习
查看>>
trove 基于 centos7 制作 mysql5.6 镜像
查看>>
结合i节点和数据块分析linux中软链接和硬链接的区别
查看>>
Heartbeat crm的配置
查看>>
我的友情链接
查看>>
Windows Server 2012_Install_Guide
查看>>
ISA Server搭建站点对站点×××
查看>>
我的友情链接
查看>>