单例的作用是独一无二,利用像单例这样的单件对象,可以确保程序中使用的全局资源只有一份。 单件常常被用来管理共享资源,例如数据库连接或者线程池。
当类只能有一个实例而且客户可以从一个众所周知的访问点访问它时。
当这个唯一实例应该是通过子类化可扩展的,并且客户应该无需更改代码就能使用一个扩展的实例时。
{
class Program
{
static void Main(string[] args)
{
SamSingleton.Instance.Display();
Console.WriteLine(SamSingleton.Instance.ToString());
Console.ReadLine();
}
}
public sealed class SamSingleton
{//sealed 防止继承,密封该类
private static string str = "";
private static readonly SamSingleton instance = new SamSingleton();//构造实例对象,STATIC声明静态变量的,静态变量只能被初始化一次
static SamSingleton()
{
str = "KKK";
}
public static SamSingleton Instance
{
get { return instance; }
}
public void Display()
{
Console.WriteLine("XXXX");
}
public override string ToString()
{
return str;
}
}
}
09年9月写的线程操作如下 感觉和单件模式有那么一点类似,但感觉还是不太对。
public class ThreadTest
{
public int _maxLoop;
public int _queueItemCount = 5;
public Queue<int> _queue;
public Random _rand;
public ThreadTest()
{
_maxLoop = 100;
_queueItemCount = 1;
_queue = new Queue<int>(_queueItemCount);
_rand = new Random();
}
}
public class MyTest
{
static void Main()
{
Console.WriteLine("Begin text");
ThreadTest tt = new ThreadTest();
Timer timer1 = new Timer(new TimerCallback(Write), tt, 1000, 2000);
Timer timer2 = new Timer(new TimerCallback(Read), tt, 1000, 3000);
Console.ReadLine();
}
static void Read(object obj)
{
ThreadTest tt=(ThreadTest)obj;
lock (tt._queue)
{
if (tt._queue.Count < 1)
{
Console.WriteLine("队列已空,读等待中...");
Monitor.Wait(tt._queue);
return;
}
tt._queue.Dequeue();
Console.WriteLine("读,队列中有{0}个元素", tt._queue.Count);
Monitor.Pulse(tt._queue);
}
}
static void Write(object obj)
{
ThreadTest tt=(ThreadTest)obj;
lock (tt._queue)
{
if (tt._queue.Count >= 5)
{
Console.WriteLine("队列已满,写等待中...");
Monitor.Wait(tt._queue);
return;
}
// Thread.Sleep(1000);
tt._queue.Enqueue(tt._rand.Next());
Console.WriteLine("写,队列中有{0}个元素", tt._queue.Count);
Monitor.Pulse(tt._queue);
}
}
}
Main()函数是C#程序的入口,起始线程可以称之为主线程。
后台线程跟前台线程只有一个区别,那就是后台线程不妨碍程序的终止.
关键字lock,它可以把一段代码定义为互斥段(critical section),互斥段在一个时刻内只允许一个线程进入执行,而其他线程必须等待。在C#中,关键字lock定义如下:lock(expression) statement_block
Monitor类可以锁定一个对象,一个线程只有得到这把锁才可以对该对象进行操作。对象锁机制保证了在可能引起混乱的情况下一个时刻只有一个线程可以访问这个对象。Monitor.Pulse()方法通知等待队列中的第一个线程,于是该线程被转移到预备队列中,当对象锁被释放时,在预备队列中的线程可以立即获得对象锁。
bool readerFlag = false; // 状态标志,为true时可以读取,为false则正在写入
public int ReadFromCell()
{
lock (this) // Lock关键字保证了什么,请大家看前面对lock的介绍
{
if (!readerFlag)//如果现在不可读取
{
try
{ //等待WriteToCell方法中调用Monitor.Pulse()方法
Monitor.Wait(this);
}
catch (SynchronizationLockException e)
{
Console.WriteLine(e);
}
catch (ThreadInterruptedException e)
{
Console.WriteLine(e);
}
}
Console.WriteLine("Consume: {0}", cellContents);
readerFlag = false; //重置readerFlag标志,表示消费行为已经完成
Monitor.Pulse(this); //通知WriteToCell()方法(该方法在另外一个线程中执行,等待中)
}
return cellContents;
}
public void WriteToCell(int n)
{
lock (this)
{
if (readerFlag)
{
try
{
Monitor.Wait(this);
}
catch (SynchronizationLockException e)
{ //当同步方法(指Monitor类除Enter之外的方法)在非同步的代码区被调用
Console.WriteLine(e);
}
catch (ThreadInterruptedException e)
{ //当线程在等待状态的时候中止
Console.WriteLine(e);
}
}
cellContents = n;
Console.WriteLine("Produce: {0}", cellContents);
readerFlag = true;
Monitor.Pulse(this); //通知另外一个线程中正在等待的ReadFromCell()方法
}
}
Mutex.WaitOne()方法等待Mutex对象被释放,如果它等待的Mutex对象被释放了,它就自动拥有这个对象,直到它调用Mutex.ReleaseMutex()方法释放这个对象,而在此期间,其他想要获取这个Mutex对象的线程都只有等待。// AutoResetEvent.Set()方法设置它为有信号状态// AutoResetEvent.Reset()方法设置它为无信号状态
static Mutex gM1=new Mutex(true,"MyMutex");
{
gM1.WaitOne( );
gM1.ReleaseMutex( );
}
static AutoResetEvent Event1 = new AutoResetEvent(false);
static AutoResetEvent Event2 = new AutoResetEvent(false);
AutoResetEvent[] evs = new AutoResetEvent[2]{Event1,Event2};
Event1.Set( ) ; Event2.Set( ) ;
WaitHandle.WaitAll(evs);
在多线程的程序中,经常会出现两种情况:
一种情况: 应用程序中,线程把大部分的时间花费在等待状态,等待某个事件发生,然后才能给予响应,这一般使用ThreadPool(线程池)来解决;
for (int iItem=0;iItem < MaxCount;iItem++)
{ //插入队列元素
Console.WriteLine("Queue to Thread Pool {0}", iItem);
ThreadPool.QueueUserWorkItem(new WaitCallback(oAlpha.Beta), new SomeState(iItem));
}
ManualResetEvent eventX = new ManualResetEvent(false);
eventX.WaitOne(Timeout.Infinite,true); //等待事件的完成,即线程调用ManualResetEvent.Set()方法 //WaitOne()方法使调用它的线程等待直到eventX.Set()方法被调用
public static int iCount = 0;
Interlocked.Increment(ref iCount);
另一种情况:线程平时都处于休眠状态,只是周期性地被唤醒,这一般使用Timer(定时器)来解决;
Timer timer = new Timer(timerDelegate, s,1000, 1000);
// 第一个参数:指定了TimerCallback 委托,表示要执行的方法;
// 第二个参数:一个包含回调方法要使用的信息的对象,或者为空引用;
// 第三个参数:延迟时间——计时开始的时刻距现在的时间,单位是毫秒,指定为“0”表示立即启动计时器;
// 第四个参数:定时器的时间间隔——计时开始以后,每隔这么长的一段时间,TimerCallback所代表的方法将被调用一次,单位也是毫秒。
class TimerExampleState
{
public int counter = 0;
public Timer tmr;
}
class App
{
public static void Main()
{
TimerExampleState s = new TimerExampleState();
//创建代理对象TimerCallback,该代理将被定时调用
TimerCallback timerDelegate = new TimerCallback(CheckStatus);
//创建一个时间间隔为1s的定时器
Timer timer = new Timer(timerDelegate, s,1000, 1000);
s.tmr = timer;
//主线程停下来等待Timer对象的终止
while(s.tmr != null)
Thread.Sleep(0);
Console.WriteLine("Timer example done.");
Console.ReadLine();
}
//下面是被定时调用的方法
static void CheckStatus(Object state)
{
TimerExampleState s =(TimerExampleState)state;
s.counter++;
Console.WriteLine("{0} Checking Status {1}.",DateTime.Now.TimeOfDay, s.counter);
if(s.counter == 5)
{ //使用Change方法改变了时间间隔
(s.tmr).Change(1000,2000);
Console.WriteLine("changed");
}
if(s.counter == 10)
{
Console.WriteLine("disposing of timer");
s.tmr.Dispose();
s.tmr = null;
}
}
}