hei 7
0
t 是一个线程
//这句话(t.Join();)在那个线程中执行,那么就阻塞了那个线程,那个线程要等待t线程执行完毕后,然后才会继续。
t.Join();//阻塞当前"主线程",等待t线程执行完毕后,继续主线程的执行。
t.Join(1000); //1000表示超时时间,这里“主线程”会等待t线程执行完毕,只等待1000毫秒,超过1000毫秒后,“主线程”继续执行。
1 线程池的作用
//线程池的使用:
ThreadPool.QueueUserWorkItem(new WaitCallback((obj) =>
{
Console.WriteLine("方法三:" + Thread.CurrentThread.ManagedThreadId);
//这里的方法就是要进行异步执行的方法
for (int i = 0; i < 10; i++)
{
Console.WriteLine("*");
Thread.Sleep(300);
}
}));
1 子线程改变主线程控件的方法
#region 子线程给主线程设置控件值
private string UpdatText(string msg)
{
richTextBox1.AppendText(msg + "
");
return msg;
}
public void ThreadMethodTxt(string n)
{
IAsyncResult ar= this.BeginInvoke(updateText, n);
string res = this.EndInvoke(ar).ToString();
this.BeginInvoke(updateText, "返回数据" + res);
}
//创建一个委托,是为访问TextBox控件服务的。
public delegate string UpdateText(string msg);
/// <summary>
/// 定义一个委托变量
/// </summary>
public UpdateText updateText = null;
/// <summary>
/// 子线程给主线程赋值
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button1_Click(object sender, EventArgs e)
{
updateText = new UpdateText(UpdatText);
Thread objThread = new Thread(new ThreadStart(delegate()
{
ThreadMethodTxt(textBox1.Text);
}));
objThread.IsBackground = true;
objThread.Start();
}
#endregion
1.1 子线程改变主线程的方法(抽奖机的运用)
private void button1_Click(object sender, EventArgs e)
{
List<Label> listLabel = new List<Label>();
List<Thread> listThread = new List<Thread>();
Random rdm = new Random();
if (listThread.Count == 0)
{
//开始启动线程
//有几个Label就创建几个线程
for (int i = 0; i < listLabel.Count; i++)
{
Thread t = new Thread(new ParameterizedThreadStart((index) =>
{
//index这个参数就表示当前这个线程要修改的Label的索引
while (true)
{
int r = rdm.Next(0, 10);
//这里不能直接使用该Label控件,这样的话就会出现“跨线程访问控件”的问题
//listLabel[(int)index].Text = r.ToString();
//解决:使用控件的Invoke()方法
listLabel[(int)index].Invoke(new Action<int, string>((lblIndex, randomVal) =>
{
listLabel[lblIndex].Text = randomVal;
}), index, r.ToString());
Thread.Sleep(50);
}
}));
listThread.Add(t);
t.IsBackground = true;
t.Start(i);//启动线程的时候把当前循环的Label的下标传进来。
}
}
}
2 通过启动一新线程,执行带返回值的方法BackgroundWorker
#region 通过启动一新线程,执行带返回值的方法BackgroundWorker
Console.WriteLine("Main(string[] args)方法中:当前执行的线程编号:{0}", Thread.CurrentThread.ManagedThreadId);
//BackgroundWorker
//创建一个后台执行者对象
BackgroundWorker backWorker = new BackgroundWorker();
//设置该对象要在后台执行的方法
backWorker.DoWork += new DoWorkEventHandler(backWorker_DoWork);
//设置另外一个事件:当程序执行完毕后触发的事件
backWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backWorker_RunWorkerCompleted);
//开始执行
backWorker.RunWorkerAsync(new int[] { 1, 100 });
Console.WriteLine("主线程继续.......");
Console.ReadKey();
//Task
#endregion
//当后台方法执行完毕后触发的事件
static void backWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
Console.WriteLine("backWorker_RunWorkerCompleted方法中:当前执行的线程编号:{0}", Thread.CurrentThread.ManagedThreadId);
Console.WriteLine("最后输出结果是:{0}", e.Result);
}
//要在后台执行的方法
static void backWorker_DoWork(object sender, DoWorkEventArgs e)
{
Console.WriteLine("backWorker_DoWork方法中:当前执行的线程编号:{0}", Thread.CurrentThread.ManagedThreadId);
if (e.Argument != null)
{
int[] arr = e.Argument as int[];
//把方法调用完毕后的值赋值给e.Result
e.Result = Sum(arr[0], arr[1]);
}
}
static int Sum(int from, int to)
{
int sum = 0;
for (int i = from; i <= to; i++)
{
sum += i;
}
return sum;
}
3 拷贝文件的进度条
private void button1_Click(object sender, EventArgs e)
{
//初始化进度条
InitialProgressBar();
//创建一个独立的线程来执行文件拷贝操作,这样就可以防止阻塞主线程了。
Thread t1 = new Thread(new ThreadStart(() =>
{
//拷贝文件
string source = textBox1.Text.Trim();
string target = textBox2.Text.Trim();
FileCopy(source, target);
}));
t1.Start();
}
private void InitialProgressBar()
{
this.progressBar1.Maximum = 100;
this.progressBar1.Minimum = 0;
this.progressBar1.Value = 0;
}
private void FileCopy(string source, string target)
{
using (FileStream fsRead = File.OpenRead(source))
{
using (FileStream fsWrite = File.OpenWrite(target))
{
//缓冲区
byte[] buffers = new byte[1024 * 1024 * 10];//10MB
//读取一次
int r = fsRead.Read(buffers, 0, buffers.Length);
//判断本次是否读取到了数据
while (r > 0)
{
//把读取到的数据写入到fsWrite中
fsWrite.Write(buffers, 0, r);
int val = (int)(fsWrite.Position * 1.0 / fsRead.Length * 100);
//progressBar1.Value = (int)(fsWrite.Position * 1.0 / fsRead.Length * 100);
progressBar1.Invoke(new Action<int>(v =>
{
progressBar1.Value = v;
}), val);
r = fsRead.Read(buffers, 0, buffers.Length);
}
}
}
this.Invoke(new Action(() =>
{
this.Text = "拷贝完毕!";
}));
}
4 线程并行计算
Stopwatch watch = new Stopwatch();
watch.Start();
Parallel.For(0, 5, new Action<int>(i =>
{
Console.WriteLine("===" + Thread.CurrentThread.ManagedThreadId + "===");
Console.WriteLine(i);
Thread.Sleep(1000);
}));
watch.Stop();
Console.WriteLine(watch.Elapsed);
Console.ReadKey();
5 线程池
1 //////WaitCallback
//////线程启动线程都是默认 后台线程。
//////交给线程池的工作任务执行顺序是不确定。
ThreadPool.QueueUserWorkItem(delegate(object state)
{
Console.WriteLine(state.ToString()+"当前执行的线程是:"+Thread.CurrentThread.ManagedThreadId);
}, "ssss");
2 ThreadPool.QueueUserWorkItem(new WaitCallback((s) =>
{
Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
}));
//int maxThread = 0;
//int maxCompleteThread = 0;
//ThreadPool.GetMaxThreads(out maxThread,out maxCompleteThread);
//Console.WriteLine(maxThread+" " +maxCompleteThread);
6 Task 4.0 才有的新功能,是在线程池中的线程
6.1
//这里面使用的线程是线程池里面的线程
//第一种开启一个线程池工作任务的方法
Task t1 = new Task(() =>
{
Thread.Sleep(2000);
Console.WriteLine("当前的线程是:"+Thread.CurrentThread.ManagedThreadId);
});
t1.Start();
t1.Wait();//让当前主线程停下来等待 工作任务完成。
6.2
//第二种开始一个线程池工作任务项
Task t1 = Task.Factory.StartNew(() =>//开启一个线程池工作任务,并执行了。
{
Thread.Sleep(2000);
Console.WriteLine("当前的线程是:" + Thread.CurrentThread.ManagedThreadId);
});
t1.Wait();//让当前主线程停下来等待 工作任务完成。
6.3
//第二种开始一个线程池工作任务项
Task t1 = Task.Factory.StartNew(() =>//开启一个线程池工作任务,并执行了。
{
Thread.Sleep(2000);
Console.WriteLine("当前的线程是:" + Thread.CurrentThread.ManagedThreadId);
});
Task t2 = Task.Factory.StartNew(() =>//开启一个线程池工作任务,并执行了。
{
Thread.Sleep(2000);
Console.WriteLine("当前的线程是:" + Thread.CurrentThread.ManagedThreadId);
});
Task t3 = Task.Factory.StartNew(() =>//开启一个线程池工作任务,并执行了。
{
Thread.Sleep(3000);
Console.WriteLine("当前的线程是:" + Thread.CurrentThread.ManagedThreadId);
});
Task.WaitAny(t1, t2, t3);//WaitAny:等其中一个工作任务完成就往下执行。
//WaitAll:是等待所有的线程工作任务都完成后再往下走。
#region 线程通知
//AutoResetEvent 线程安全类
private static AutoResetEvent waitHand = new AutoResetEvent(false); //像构造函数中传入false 表示没有收到通知
private void button2_Click(object sender, EventArgs e)
{
Thread thread = new Thread(new ParameterizedThreadStart(Add));
thread.IsBackground = true;
thread.Start("3");
//等待直到收到通知在往下执行
waitHand.WaitOne();
MessageBox.Show("Finish");
}
private void Add(object a)
{
MessageBox.Show(a.ToString());
//通知其他线程该线程已经完成
waitHand.Set();
}
#endregion