1.获取对当前线程的引用,只需要调用静态属性Thread.CurrentThread; Thread.GetDomain();//获取当前线程所在的应用程序域;Thread.CurrentContext;获取当前操作操作线程的上下文。
2.几乎无法控制底层系统和CLR对线程的调度。
3.原子性操作在多线程环境下总是线程安全的。通常的操作都不是原子操作,包括++i,赋值操作等。
4.通过Invoke方法调用委托,实际上是等待委托函数调用完成返回后,接着运行,这里并没有创建一个新的线程,而是同一个线程。(同步)
委托同步调用:
public delegate string TestDelegate(int a);
public class MyClass
{
private void Func1()
{
TestDelegate test = new TestDelegate(Func2);
string result = Func2(2);
test.Invoke(3); //两种同步调用
}
private string Func2(int a)
{
Thread.Sleep(3000);
Thread t = Thread.CurrentThread;
int id = t.ManagedThreadId;
return (a.ToString() + id.ToString());
}
}
5.通过BeginInvoke调用委托(异步)
声明的委托编译器帮助生成了三个函数
异步调用:
public delegate string TestDelegate(int a);
public class MyClass
{
private void Func1()
{
TestDelegate test = new TestDelegate(Func2);
string result = Func2(2);
test.Invoke(3); //两种同步调用
IAsyncResult iret = test.BeginInvoke(3, null, null);
Console.WriteLine("主线程没有暂停而是继续执行!");
result = test.EndInvoke(iret);
Console.WriteLine("在这之前需要等待次线程执行返回!");
}
private string Func2(int a)
{
Thread.Sleep(3000);
Thread t = Thread.CurrentThread;
int id = t.ManagedThreadId;
return (a.ToString() + id.ToString());
}
}
可以通过轮询判断IAsyncResult.IsCompleted 属性来获取次线程是否执行完成,但是这并高效;可以让次线程执行完成后主动通知主线程。
可以在BeginInvoke时候提供一个System.AsyncCallBack对象,当异步调用完成时,委托会调用这个指定的方法。
如下:
public delegate string TestDelegate(int a);
public class MyClass
{
private bool isOk = false;
private void Func1()
{
TestDelegate test = new TestDelegate(Func2);
IAsyncResult iret = test.BeginInvoke(2, new AsyncCallback(Func3), "传入自定义参数");
Console.WriteLine("主线程没有暂停而是继续执行!");
string result = test.EndInvoke(iret);
Console.WriteLine("在这之前需要等待次线程执行返回!");
while (!isOk)
{
}
Console.WriteLine("the end");
}
private void Func3(IAsyncResult ar) //次线程在调用异步委托完成时将以同步方式调用该方法,这里的ar参数实际上就是由BeginInvoke返回值传入
{
Thread t = Thread.CurrentThread;
Console.WriteLine(t.ManagedThreadId);
AsyncResult ar_1 = (AsyncResult)ar;
TestDelegate a = (TestDelegate)ar_1.AsyncDelegate;
string str = (string)ar_1.AsyncState;
string result = a.EndInvoke(ar_1);
isOk = true;
}
private string Func2(int a)
{
Thread.Sleep(3000);
Thread t = Thread.CurrentThread;
int id = t.ManagedThreadId;
return (a.ToString() + id.ToString());
}
}
6.使用Thread
System.Threading命名空间部分类型
Interlocked:为多个线程共享访问的类型提供原子操作。
Monitor :使用锁定和等待信号来同步线程对象。C#lock关键字在后台使用的就是Monitor对象。
ParameterizedThreadStart:委托,它允许线程调用包含任意多个参数的方法
Thread :代表CLR中执行的线程。使用这个类型,能够在初始的应用程序域中创建额外的线程。
ThreadPool:用于和一个进程中的(由CLR维护的)线程池交互。
Timer:提供指定时间间隔执行方法的机制
TimerCallback:该委托类型应与Timer类型一起使用
示例:
public class ThreadPara
{
public ThreadPara()
{
this.Id = default(int);
this.Name = "";
}
public ThreadPara(int id, string name)
{
this.Id = id;
this.Name = name;
}
public int Id { get; set; }
public string Name { get; set; }
}
public class MyClass1
{
private void Func1()
{
Thread t = new Thread(ThreadMethoed); //无参线程入口参数
t.IsBackground = true;
t.Start();
Thread t_1 = new Thread(new ThreadStart(ThreadMethoed));//另一种无参
Thread t_2 = new Thread(new ParameterizedThreadStart(ThMethoedOnePara)); //有一个参数
t_2.Start("aaaa");
Thread t_3 = new Thread(new ParameterizedThreadStart(ThMethoedMorePara)); //多个参数
ThreadPara thPara = new ThreadPara();
t_3.Start(thPara);
}
private void ThMethoedMorePara(object obj)
{
ThreadPara para = (ThreadPara)obj;
Console.WriteLine(para.Id + para.Name);
}
private void ThMethoedOnePara(object obj)
{
string str = (string)obj;
Console.WriteLine(str);
}
private void ThreadMethoed()
{
Console.WriteLine("另一个线程");
}
}
{
AutoResetEvent autoE = new AutoResetEvent(false);
private void Func1()
{
Thread t = new Thread(ThreadMethoed); //无参线程入口参数
t.Start();
Thread t_3 = new Thread(new ParameterizedThreadStart(ThMethoedMorePara)); //多个参数
ThreadPara thPara = new ThreadPara(2, "aaaa");
t_3.Start(thPara);
autoE.Set();
}
private void ThMethoedMorePara(object obj)
{
autoE.WaitOne();
ThreadPara para = (ThreadPara)obj;
Console.WriteLine(para.Id + para.Name);
}
private void ThreadMethoed()
{
autoE.WaitOne();
Console.WriteLine("另一个线程");
}
}
8.前台线程和后台线程
前台线程:能阻止应用程序的终结,知道所有的前台线程都终结后,CLR才能关闭应用程序(即卸载承载的应用程序域)。
后台线程:被CLR认为是程序执行中可做出牺牲的途径,即在任何时候都可以被忽略。如果所有前台线程终止,当前应用程序域被卸载,所有后台线程也会被自动终止。
9.使用lock(首选)关键字,同步访问共享资源
该关键字允许定义一段线程同步的代码块。lock关键字需要定义一个标记(即一个对象的引用),线程在进入锁定范围的时候必须获得这个标记。通常定义一个私有的对象(object类型)作为锁标识。
public void FuncLock()
{
lock (obj)
{
}
}
10.使用System.Monitor同步
lock(obj)
{
}
等价为:
try
{
Monitor.Enter(obj)
}
catch()
{}
finally
{
Monitor.Exit(obj)
}
11.System.Threading.Interlocked类型进行同步
部分静态成员
Decrement() 安全的减一
Exchange() 安全的交换
Increment() 安全的加一
示例:
public int AddOne(ref int val)
{
int newVal = Interlocked.Increment(ref val);
return newVal;
}
12.使用特性[Synchronization]进行同步
这个类级别的特性有效的使对象的所有示例的成员都保持线程安全。