您的位置:首页 > 其它

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

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

应用场景:

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

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

不废话了,直接上代码:

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

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

/**************************************** 模块头 *****************************************\
* 模块名:TicketFactory.cs
* 项目名:MultiThreadSync
* 版权 (c) markeluo
*
* 本项目演示了在多线程并发对同一个对象进行操作,如何保证对象的唯一性
*
\*****************************************************************************************/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MultiThreadSync
{
/// <summary>
/// 余票处理类(查询余票、购票、退票)
/// </summary>
public class TicketFactory
{
private static TicketFactory ticketmanager = new TicketFactory();
/// <summary>
/// 锁定对象
/// </summary>
private static object _sysobj = new object();
/// <summary>
/// 余票处理 实例 单例
/// </summary>
public static TicketFactory Instanc
{
get
{
return ticketmanager;
}
}

/// <summary>
/// 余票总数量 (假设此数据是从数据库中获取的)
/// </summary>
private int TicketCount = 10000;

/// <summary>
/// 查询余票
/// </summary>
/// <returns></returns>
public int GetTickets()
{
lock (_sysobj)
{
//暂停1秒以测试效果
System.Threading.Thread.Sleep(1000);

return TicketCount;
//实际应该从数据库中获取
}
}

/// <summary>
/// 退票/增加票数
/// </summary>
/// <returns></returns>
public void AddTickets(int Count)
{
lock (_sysobj)
{
//暂停2秒以测试效果
System.Threading.Thread.Sleep(2000);

TicketCount += Count;
//实际应该添加到数据库
}
}

/// <summary>
/// 购票
/// </summary>
/// <param name="Count"></param>
public void BuyTickets(int Count)
{
lock (_sysobj)
{
//暂停3秒以测试效果
System.Threading.Thread.Sleep(3000);

TicketCount -= Count;
//实际应该从数据库中移除相应的专利数量
}
}

}
}


2.多线程调用测试类

/**************************************** 模块头 *****************************************\
* 模块名:StartMultiThread.cs
* 项目名:MultiThreadSync
* 版权 (c) markeluo
*
* 本项目演示了在多线程并发对同一个对象进行操作,如何保证对象的唯一性
*
\*****************************************************************************************/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MultiThreadSync
{
/// <summary>
/// 多线程测试类
/// </summary>
public class StartMultiThread
{
public delegate void DelEventArg(string TipInfo);

/// <summary>
/// 余票数量处理提示
/// </summary>
public event DelEventArg TickedCountChangeEvent;

public void Start()
{
//线程1
System.Threading.Thread Thread1 = new System.Threading.Thread(new System.Threading.ThreadStart(TicketManager1));
Thread1.IsBackground = true;
Thread1.Start();

//线程2
System.Threading.Thread Thread2 = new System.Threading.Thread(new System.Threading.ThreadStart(TicketManager2));
Thread2.IsBackground = true;
Thread2.Start();

//线程3
System.Threading.Thread Thread3 = new System.Threading.Thread(new System.Threading.ThreadStart(TicketManager3));
Thread3.IsBackground = true;
Thread3.Start();

//线程4
System.Threading.Thread Thread4 = new System.Threading.Thread(new System.Threading.ThreadStart(TicketManager4));
Thread4.IsBackground = true;
Thread4.Start();

}

/// <summary>
/// 余票处理1
/// </summary>
private void TicketManager1()
{
DateTime _startTime = DateTime.Now;
TicketFactory.Instanc.AddTickets(2);
if (TickedCountChangeEvent != null)
{
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"));
TickedCountChangeEvent(strTip);
}

_startTime = DateTime.Now;
TicketFactory.Instanc.BuyTickets(1);
if (TickedCountChangeEvent != null)
{
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"));
TickedCountChangeEvent(strTip);
}

_startTime = DateTime.Now;
int _Count = TicketFactory.Instanc.GetTickets();
if (TickedCountChangeEvent != null)
{
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);
TickedCountChangeEvent(strTip);
}
}

/// <summary>
/// 余票处理2
/// </summary>
private void TicketManager2()
{
DateTime _startTime = DateTime.Now;
TicketFactory.Instanc.AddTickets(2);
if (TickedCountChangeEvent != null)
{
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"));
TickedCountChangeEvent(strTip);
}

_startTime = DateTime.Now;
TicketFactory.Instanc.BuyTickets(1);
if (TickedCountChangeEvent != null)
{
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"));
TickedCountChangeEvent(strTip);
}

_startTime = DateTime.Now;
int _Count = TicketFactory.Instanc.GetTickets();
if (TickedCountChangeEvent != null)
{
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);
TickedCountChangeEvent(strTip);
}
}

/// <summary>
/// 余票处理3
/// </summary>
private void TicketManager3()
{
DateTime _startTime = DateTime.Now;
TicketFactory.Instanc.AddTickets(2);
if (TickedCountChangeEvent != null)
{
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"));
TickedCountChangeEvent(strTip);
}

_startTime = DateTime.Now;
TicketFactory.Instanc.BuyTickets(1);
if (TickedCountChangeEvent != null)
{
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"));
TickedCountChangeEvent(strTip);
}

_startTime = DateTime.Now;
int _Count = TicketFactory.Instanc.GetTickets();
if (TickedCountChangeEvent != null)
{
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);
TickedCountChangeEvent(strTip);
}
}

/// <summary>
/// 余票处理4
/// </summary>
private void TicketManager4()
{
DateTime _startTime = DateTime.Now;
TicketFactory.Instanc.AddTickets(2);
if (TickedCountChangeEvent != null)
{
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"));
TickedCountChangeEvent(strTip);
}

_startTime = DateTime.Now;
TicketFactory.Instanc.BuyTickets(1);
if (TickedCountChangeEvent != null)
{
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"));
TickedCountChangeEvent(strTip);
}

_startTime = DateTime.Now;
int _Count = TicketFactory.Instanc.GetTickets();
if (TickedCountChangeEvent != null)
{
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);
TickedCountChangeEvent(strTip);
}
}

}
}


3.界面显示

/**************************************** 模块头 *****************************************\
* 模块名:Form1.cs
* 项目名:MultiThreadSync
* 版权 (c) markeluo
*
* 本项目演示了在多线程并发对同一个对象进行操作,如何保证对象的唯一性
*
\*****************************************************************************************/

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace MultiThreadSync
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}

private void button1_Click(object sender, EventArgs e)
{
StartMultiThread _start = new StartMultiThread();
_start.TickedCountChangeEvent += new StartMultiThread.DelEventArg(_start_TickedCountChangeEvent);
_start.Start();
}

/// <summary>
/// 事件订阅处理
/// </summary>
/// <param name="TipInfo"></param>
void _start_TickedCountChangeEvent(string TipInfo)
{
if (this.InvokeRequired)
{
this.BeginInvoke(new StartMultiThread.DelEventArg(ShowTipInfo), new object[] { TipInfo});
}
else
{
ShowTipInfo(TipInfo);
}
}

/// <summary>
/// 显示多线程访问TicketFactory ,进行增删改查的时间和顺序
/// </summary>
/// <param name="TipInfo"></param>
private void ShowTipInfo(string TipInfo)
{
this.ListBoxTips.Items.Add(TipInfo);
}

}
}


源码下载
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: