• .NET 多线程同步 / 并发操作数据唯一


       在实际应用过程中很多情况下涉及大批量、频繁访问,这样就会存在并发操作,如何保证数据的唯一正确性就成了一个问题,以下将自己为别人做的一个示例展示给大家,什么不足的地方大家也提提意见!

      应用场景:

           售票系统,假如涉及到以下几种简单数据访问操作:1.余票查询;2.购票;3:临时增加售票/退票  ,如果访问量较大,很多个用户同时访问时。

           如1和2同时操作,2和3同时操作,1和3同时操作,就可能导致获取的数据信息不准确,这里我们就需要的效果就是当任何一个用户在进行如上的1或2或3操作时,其它用户都处于等待状态,只有前一个用户执行完后,其它用户方可进行。

           不废话了,直接上代码:

       1.处理类 TicketFactory(增/删/查)

           此处理类即可保证查询余票、购票、退票 时,数据的唯一准确性

     1 /**************************************** 模块头 *****************************************\
    2 * 模块名:TicketFactory.cs
    3 * 项目名:MultiThreadSync
    4 * 版权 (c) markeluo
    5 *
    6 * 本项目演示了在多线程并发对同一个对象进行操作,如何保证对象的唯一性
    7 *
    8 \*****************************************************************************************/
    9
    10 using System;
    11 using System.Collections.Generic;
    12 using System.Linq;
    13 using System.Text;
    14
    15 namespace MultiThreadSync
    16 {
    17 /// <summary>
    18 /// 余票处理类(查询余票、购票、退票)
    19 /// </summary>
    20 public class TicketFactory
    21 {
    22 private static TicketFactory ticketmanager = new TicketFactory();
    23 /// <summary>
    24 /// 锁定对象
    25 /// </summary>
    26 private static object _sysobj = new object();
    27 /// <summary>
    28 /// 余票处理 实例 单例
    29 /// </summary>
    30 public static TicketFactory Instanc
    31 {
    32 get
    33 {
    34 return ticketmanager;
    35 }
    36 }
    37
    38 /// <summary>
    39 /// 余票总数量 (假设此数据是从数据库中获取的)
    40 /// </summary>
    41 private int TicketCount = 10000;
    42
    43 /// <summary>
    44 /// 查询余票
    45 /// </summary>
    46 /// <returns></returns>
    47 public int GetTickets()
    48 {
    49 lock (_sysobj)
    50 {
    51 //暂停1秒以测试效果
    52 System.Threading.Thread.Sleep(1000);
    53
    54 return TicketCount;
    55 //实际应该从数据库中获取
    56 }
    57 }
    58
    59 /// <summary>
    60 /// 退票/增加票数
    61 /// </summary>
    62 /// <returns></returns>
    63 public void AddTickets(int Count)
    64 {
    65 lock (_sysobj)
    66 {
    67 //暂停2秒以测试效果
    68 System.Threading.Thread.Sleep(2000);
    69
    70 TicketCount += Count;
    71 //实际应该添加到数据库
    72 }
    73 }
    74
    75 /// <summary>
    76 /// 购票
    77 /// </summary>
    78 /// <param name="Count"></param>
    79 public void BuyTickets(int Count)
    80 {
    81 lock (_sysobj)
    82 {
    83 //暂停3秒以测试效果
    84 System.Threading.Thread.Sleep(3000);
    85
    86 TicketCount -= Count;
    87 //实际应该从数据库中移除相应的专利数量
    88 }
    89 }
    90
    91 }
    92 }


    2.多线程调用测试类

      1 /**************************************** 模块头 *****************************************\
    2 * 模块名:StartMultiThread.cs
    3 * 项目名:MultiThreadSync
    4 * 版权 (c) markeluo
    5 *
    6 * 本项目演示了在多线程并发对同一个对象进行操作,如何保证对象的唯一性
    7 *
    8 \*****************************************************************************************/
    9
    10 using System;
    11 using System.Collections.Generic;
    12 using System.Linq;
    13 using System.Text;
    14
    15 namespace MultiThreadSync
    16 {
    17 /// <summary>
    18 /// 多线程测试类
    19 /// </summary>
    20 public class StartMultiThread
    21 {
    22 public delegate void DelEventArg(string TipInfo);
    23
    24 /// <summary>
    25 /// 余票数量处理提示
    26 /// </summary>
    27 public event DelEventArg TickedCountChangeEvent;
    28
    29 public void Start()
    30 {
    31 //线程1
    32 System.Threading.Thread Thread1 = new System.Threading.Thread(new System.Threading.ThreadStart(TicketManager1));
    33 Thread1.IsBackground = true;
    34 Thread1.Start();
    35
    36 //线程2
    37 System.Threading.Thread Thread2 = new System.Threading.Thread(new System.Threading.ThreadStart(TicketManager2));
    38 Thread2.IsBackground = true;
    39 Thread2.Start();
    40
    41 //线程3
    42 System.Threading.Thread Thread3 = new System.Threading.Thread(new System.Threading.ThreadStart(TicketManager3));
    43 Thread3.IsBackground = true;
    44 Thread3.Start();
    45
    46 //线程4
    47 System.Threading.Thread Thread4 = new System.Threading.Thread(new System.Threading.ThreadStart(TicketManager4));
    48 Thread4.IsBackground = true;
    49 Thread4.Start();
    50
    51 }
    52
    53 /// <summary>
    54 /// 余票处理1
    55 /// </summary>
    56 private void TicketManager1()
    57 {
    58 DateTime _startTime = DateTime.Now;
    59 TicketFactory.Instanc.AddTickets(2);
    60 if (TickedCountChangeEvent != null)
    61 {
    62 string strTip = string.Format("线程1 {0}-{1} 退票2张!", _startTime.ToString("yyyy-MM-dd HH:mm:ss.fff"), DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"));
    63 TickedCountChangeEvent(strTip);
    64 }
    65
    66 _startTime = DateTime.Now;
    67 TicketFactory.Instanc.BuyTickets(1);
    68 if (TickedCountChangeEvent != null)
    69 {
    70 string strTip = string.Format("线程1 {0}-{1} 购票1张!", _startTime.ToString("yyyy-MM-dd HH:mm:ss.fff"), DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"));
    71 TickedCountChangeEvent(strTip);
    72 }
    73
    74 _startTime = DateTime.Now;
    75 int _Count = TicketFactory.Instanc.GetTickets();
    76 if (TickedCountChangeEvent != null)
    77 {
    78 string strTip = string.Format("线程1 {0}-{1} 查询余票,还剩{2}张!", _startTime.ToString("yyyy-MM-dd HH:mm:ss.fff"), DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), _Count);
    79 TickedCountChangeEvent(strTip);
    80 }
    81 }
    82
    83 /// <summary>
    84 /// 余票处理2
    85 /// </summary>
    86 private void TicketManager2()
    87 {
    88 DateTime _startTime = DateTime.Now;
    89 TicketFactory.Instanc.AddTickets(2);
    90 if (TickedCountChangeEvent != null)
    91 {
    92 string strTip = string.Format("线程2 {0}-{1} 退票2张!", _startTime.ToString("yyyy-MM-dd HH:mm:ss.fff"), DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"));
    93 TickedCountChangeEvent(strTip);
    94 }
    95
    96 _startTime = DateTime.Now;
    97 TicketFactory.Instanc.BuyTickets(1);
    98 if (TickedCountChangeEvent != null)
    99 {
    100 string strTip = string.Format("线程2 {0}-{1} 购票1张!", _startTime.ToString("yyyy-MM-dd HH:mm:ss.fff"), DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"));
    101 TickedCountChangeEvent(strTip);
    102 }
    103
    104 _startTime = DateTime.Now;
    105 int _Count = TicketFactory.Instanc.GetTickets();
    106 if (TickedCountChangeEvent != null)
    107 {
    108 string strTip = string.Format("线程2 {0}-{1} 查询余票,还剩{2}张!", _startTime.ToString("yyyy-MM-dd HH:mm:ss.fff"), DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), _Count);
    109 TickedCountChangeEvent(strTip);
    110 }
    111 }
    112
    113 /// <summary>
    114 /// 余票处理3
    115 /// </summary>
    116 private void TicketManager3()
    117 {
    118 DateTime _startTime = DateTime.Now;
    119 TicketFactory.Instanc.AddTickets(2);
    120 if (TickedCountChangeEvent != null)
    121 {
    122 string strTip = string.Format("线程3 {0}-{1} 退票2张!", _startTime.ToString("yyyy-MM-dd HH:mm:ss.fff"), DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"));
    123 TickedCountChangeEvent(strTip);
    124 }
    125
    126 _startTime = DateTime.Now;
    127 TicketFactory.Instanc.BuyTickets(1);
    128 if (TickedCountChangeEvent != null)
    129 {
    130 string strTip = string.Format("线程3 {0}-{1} 购票1张!", _startTime.ToString("yyyy-MM-dd HH:mm:ss.fff"), DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"));
    131 TickedCountChangeEvent(strTip);
    132 }
    133
    134 _startTime = DateTime.Now;
    135 int _Count = TicketFactory.Instanc.GetTickets();
    136 if (TickedCountChangeEvent != null)
    137 {
    138 string strTip = string.Format("线程3 {0}-{1} 查询余票,还剩{2}张!", _startTime.ToString("yyyy-MM-dd HH:mm:ss.fff"), DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), _Count);
    139 TickedCountChangeEvent(strTip);
    140 }
    141 }
    142
    143 /// <summary>
    144 /// 余票处理4
    145 /// </summary>
    146 private void TicketManager4()
    147 {
    148 DateTime _startTime = DateTime.Now;
    149 TicketFactory.Instanc.AddTickets(2);
    150 if (TickedCountChangeEvent != null)
    151 {
    152 string strTip = string.Format("线程4 {0}-{1} 退票2张!", _startTime.ToString("yyyy-MM-dd HH:mm:ss.fff"), DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"));
    153 TickedCountChangeEvent(strTip);
    154 }
    155
    156 _startTime = DateTime.Now;
    157 TicketFactory.Instanc.BuyTickets(1);
    158 if (TickedCountChangeEvent != null)
    159 {
    160 string strTip = string.Format("线程4 {0}-{1} 购票1张!", _startTime.ToString("yyyy-MM-dd HH:mm:ss.fff"), DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"));
    161 TickedCountChangeEvent(strTip);
    162 }
    163
    164 _startTime = DateTime.Now;
    165 int _Count = TicketFactory.Instanc.GetTickets();
    166 if (TickedCountChangeEvent != null)
    167 {
    168 string strTip = string.Format("线程4 {0}-{1} 查询余票,还剩{2}张!", _startTime.ToString("yyyy-MM-dd HH:mm:ss.fff"), DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), _Count);
    169 TickedCountChangeEvent(strTip);
    170 }
    171 }
    172
    173 }
    174 }


    3.界面显示

     1 /**************************************** 模块头 *****************************************\
    2 * 模块名:Form1.cs
    3 * 项目名:MultiThreadSync
    4 * 版权 (c) markeluo
    5 *
    6 * 本项目演示了在多线程并发对同一个对象进行操作,如何保证对象的唯一性
    7 *
    8 \*****************************************************************************************/
    9
    10 using System;
    11 using System.Collections.Generic;
    12 using System.ComponentModel;
    13 using System.Data;
    14 using System.Drawing;
    15 using System.Linq;
    16 using System.Text;
    17 using System.Windows.Forms;
    18
    19 namespace MultiThreadSync
    20 {
    21 public partial class Form1 : Form
    22 {
    23 public Form1()
    24 {
    25 InitializeComponent();
    26 }
    27
    28 private void button1_Click(object sender, EventArgs e)
    29 {
    30 StartMultiThread _start = new StartMultiThread();
    31 _start.TickedCountChangeEvent += new StartMultiThread.DelEventArg(_start_TickedCountChangeEvent);
    32 _start.Start();
    33 }
    34
    35
    36 /// <summary>
    37 /// 事件订阅处理
    38 /// </summary>
    39 /// <param name="TipInfo"></param>
    40 void _start_TickedCountChangeEvent(string TipInfo)
    41 {
    42 if (this.InvokeRequired)
    43 {
    44 this.BeginInvoke(new StartMultiThread.DelEventArg(ShowTipInfo), new object[] { TipInfo});
    45 }
    46 else
    47 {
    48 ShowTipInfo(TipInfo);
    49 }
    50 }
    51
    52 /// <summary>
    53 /// 显示多线程访问TicketFactory ,进行增删改查的时间和顺序
    54 /// </summary>
    55 /// <param name="TipInfo"></param>
    56 private void ShowTipInfo(string TipInfo)
    57 {
    58 this.ListBoxTips.Items.Add(TipInfo);
    59 }
    60
    61
    62 }
    63 }

      源码下载

  • 相关阅读:
    linux驱动开发学习一:创建一个字符设备
    如何高效的对有序数组去重
    找到缺失的第一个正整数
    .NET不可变集合已经正式发布
    中国人唯一不认可的成功——就是家庭的和睦,人生的平淡【转】
    自己动手搭建 MongoDB 环境,并建立一个 .NET HelloWorld 程序测试
    ASP.NET MVC 中如何用自定义 Handler 来处理来自 AJAX 请求的 HttpRequestValidationException 错误
    自己动手搭建 Redis 环境,并建立一个 .NET HelloWorld 程序测试
    ServiceStack 介绍
    一步一步实战扩展 ASP.NET Route,实现小写 URL、个性化 URL
  • 原文地址:https://www.cnblogs.com/luowanli/p/markeluo_MultiSysnc.html
Copyright © 2020-2023  润新知