关于多线程处理,根据自己的学习做了一下总结,算是复习用,下面主要贴一些实例Demo。看此博客建议先将.Net委托(拉姆达表达式)先学习一下,否则,看起来可能比较吃力,至少我是这样的。
为了清晰,我把标题做了红字黄底加粗显示。
1,启动线程调用无参无返回值的方法
Console.WriteLine("主线程开始");
Thread t1 = new Thread(new ThreadStart(Test1));
//可以通过IsBackground=true,把指定线程设置为后台线程。
//默认创建的进程都是“前台线程”,只有当所有“前台线程”都执行完毕后“进程”才会结束。
//后台线程在所有前台线程执行完毕后,自动退出。
t1.IsBackground = true;
t1.Start();
//在哪个线程中执行,就阻塞了哪个线程,那个线程要等待t1线程执行完毕后,然后才会继续。
//如果不理解,把t1.Join()注掉观察结果
//Join可以在在参数中设置阻塞时间,例如t1.Join(1000)
t1.Join();
Console.WriteLine("主线程结束");
Console.Read();
2,启动线程调用有参数无返回值的方法
①利用预定义的函数调用
Console.WriteLine("主线程开始");
Thread t2 = new Thread(new ParameterizedThreadStart(Test2));
t2.Start(100);
Console.WriteLine("主线程结束");
Console.Read();
②将函数封装到类中,演变成调用无参数无返回值的方法
MyClass mc = new MyClass();
mc.Num = 100;
Thread t3 = new Thread(new ThreadStart(mc.Test3));
t3.Start();
Console.Read();
class MyClass
{
private int num;
public int Num
{
get { return num; }
set { num = value; }
}
public void Test3()
{
int result = 0;
for (int i = 0; i < this.Num; i++)
{
result += i;
}
Console.WriteLine(result);
}
}
3,启动线程调用有参数有返回值得方法
①BackgroundWorker实现
BackgroundWorker backWorker = new BackgroundWorker();
backWorker.DoWork += backWorker_DoWork;
backWorker.RunWorkerCompleted += backWorker_RunWorkerCompleted;
backWorker.RunWorkerAsync(new int[] { 100 });
Console.Read();
static void backWorker_DoWork(object sender, DoWorkEventArgs e)
{
if (e.Argument != null)
{
int[] arr = e.Argument as int[];
e.Result = Test4(arr[0]);
}
}
private static void backWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
Console.WriteLine(e.Result);
}
②异步委托调用实现
A,BeginInvoke&EndInvke的方式实现
Console.WriteLine("主线程开始");
MyDel md = new MyDel(Test4);
IAsyncResult asyResult = md.BeginInvoke(100, null, null);
for (int i = 0; i < 10; i++)
{
Console.WriteLine("主线程进行中..." + i);
}
//调用EndInvoke会阻塞线程,等待异步委托执行完毕。
int sum = md.EndInvoke(asyResult);
Console.WriteLine(sum);
Console.WriteLine("主线程结束");
Console.Read();
B,回调的方式实现
MyDel md = new MyDel(Test4);
IAsyncResult asyResult = md.BeginInvoke(100, CallBack, "Test");
Console.WriteLine("主线程继续");
Console.Read();
private static void CallBack(IAsyncResult res)
{
Console.WriteLine("回调函数执行中");
AsyncResult ar = res as AsyncResult;
int sum = ((MyDel)ar.AsyncDelegate).EndInvoke(ar);
Console.WriteLine("返回值是:"+sum);
}
4,终止线程
if (t1 != null)
{
t1.Abort();
}
5,跨线程访问控件
////如果不关闭跨线程访问控件检查,会抛出异常
//Thread t2 = new Thread(new ThreadStart(() =>
//{
// this.textBox1.Text = "Hi";
//}));
//t2.IsBackground = true;
//t2.Start();
Thread t1 = new Thread(new ThreadStart(() =>
{
//利用控件的Invoke方法,将控件的操作放到创建空间的线程中进行
this.textBox1.Invoke(new Action<string>(UpdateText), "hello");
}));
t1.IsBackground = true;
t1.Start();
6,线程池
Console.WriteLine("Main thread ID:" + Thread.CurrentThread.ManagedThreadId);
ThreadPool.QueueUserWorkItem(new WaitCallback((obj) =>
{
Console.WriteLine("Thread 1 ID:" + Thread.CurrentThread.ManagedThreadId);
for (int i = 0; i < 10; i++)
{
Console.WriteLine(".");
Thread.Sleep(500);
}
}));
ThreadPool.QueueUserWorkItem(new WaitCallback((obj) =>
{
Console.WriteLine("Thread 1 ID:" + Thread.CurrentThread.ManagedThreadId);
for (int i = 0; i < 10; i++)
{
Console.WriteLine("*");
Thread.Sleep(500);
}
}));
ThreadPool.QueueUserWorkItem(new WaitCallback((obj) =>
{
Console.WriteLine("Thread 1 ID:" + Thread.CurrentThread.ManagedThreadId);
for (int i = 0; i < 10; i++)
{
Console.WriteLine("=");
Thread.Sleep(500);
}
}));
Console.WriteLine("主线程继续");
Console.Read();
7,锁机制
static long max = 100000;
static long idx = 0;
static readonly object objSync = new object();
static void Main(string[] args)
{
Thread t1 = new Thread(new ThreadStart(() =>
{
for (int i = 0; i < max; i++)
{
lock (objSync)
{
idx++;
}
}
}));
t1.IsBackground = true;
t1.Start();
for (int i = 0; i < max; i++)
{
lock(objSync)
{
idx--;
}
}
t1.Join();
Console.WriteLine("最终idx="+idx);
Console.Read();
8,单线程造成界面假死多线程解决
Random rd = new Random();
////单线程,线程一直在做死循环,无法更新界面
//while (true)
//{
// label1.Text = rd.Next(0, 10).ToString();
// label2.Text = rd.Next(0, 10).ToString();
// label3.Text = rd.Next(0, 10).ToString();
// Thread.Sleep(300);
//}
//开启一个线程专门处理界面显示
t1 = new Thread(new ThreadStart(() =>
{
while (true)
{
label1.Text = rd.Next(0, 10).ToString();
label2.Text = rd.Next(0, 10).ToString();
label3.Text = rd.Next(0, 10).ToString();
Thread.Sleep(300);
}
}));
t1.IsBackground = true;
t1.Start();