//线程同步lock Monitor
lock(this) 锁定 当前实例对象,如果有多个类实例的话,lock锁定的只是当前类实例,对其它类实例无影响。所有不推荐使用。
lock(typeof(Model))锁定的是model类的所有实例。 这里的Model是指某个类名。
lock(obj)锁定的对象是全局的私有化静态变量。外部无法对该变量进行访问。
lock 确保当一个线程位于代码的临界区时,另一个线程不进入临界区。如果其他线程试图进入锁定的代码,则它将一直等待(即被阻止),直到该对象被释放。
所以,lock的结果好不好,还是关键看锁的谁,如果外边能对这个谁进行修改,lock就失去了作用。
所以,一般情况下,使用私有的、静态的并且是只读的对象
lock(obj) { //代码段 }
//就等同于
Monitor.Enter(obj);
//代码段
Monitor.Exit(obj);
.net4.0或以上推荐用!!!!!!!!.NET 4.5引入了async和await关键字
Task对线程,线程池的封装 (没执行完程序就关闭了,是后台线程)
Task task = new Task(()=>{
void 要调用方法()
});
task.Start(); //开始线程为Start(),等待线程结束为Wait()。
线程执行完毕后调用另一个线程,也就是两个线程,有序的执行,使用ContinueWith(),
总结1:Task的使用比Thread简单很多,减少了同步,等待等等问题,唯一的遗憾是不支持Thread的IsBackground。
结论1:如果不需要使用IsBackground,那么尽情的使用Task吧。经测试,Task是后台线程,也就是Isbackground=true;
防止一个线程重复调用
if (mThread!= null)
{
if (mThread.IsAlive || mThread.ThreadState == System.Threading.ThreadState.Running)
{
mThread.Abort();
}
mThread = null;
}
mThread= new Thread(new ThreadStart(delegate()
{
}));
传统线程
Thread t = new Thread(new ParameterizedThreadStart(gp点叠加易发));//带参数
t.SetApartmentState(ApartmentState.STA);
int[] args={four,three,two,one};
t.Start(args);
t.Join(); // 等待t线程完成后,主线程才继续执行!
Thread t = new Thread(new ThreadStart(DataMapping.gp雨量计算));//不带参数
t.SetApartmentState(ApartmentState.STA);
t.Start();
后台线程:后台线程是可以随时被CLR关闭而不引发异常的
前台线程:执行确实想完成的任务,比如数据的拷贝等等
--------------------------------------------------------------------------------
线程池
//在什么情况下使用线程池来创建线程?
1.单个任务处理的时间比较短
2.需要处理的任务的数量大
子线程调用ui
调用控件的Invoke方法,Invoke方法会顺着控件树向上搜索,直到找到创建控件的那个线程(通常是主线程),然后进入那个线程改变控件的外观,确保不发生线程冲突。
this.Invoke(new EventHandler(delegate
{
button.Text="关闭";
}));
wpf的子线程调用ui
为了让后台线程访问Button的Content属性,后台线程必须将工作委托给与 UI线程关联的Dispatcher,这是通过使用Invoke(同步,立即执行)或BeginInvoke(异步,不立即执行)来完成的,通过调用BeginInvoke将异步作业排队到UI线程的Dispatcher(提供用于管理线程的工作项队列的服务)上。当UI线程处于SystemIdle(CPU空闲)状态时,在队列上推送的作业处理一个数字,并在下一次UI线程空闲时在调度程序上推送另一个调用以处理下一个数字。这可以确保UI线程始终优先于计算下一个数字,并使UI不会挂起。
this.Dispatcher.Invoke(new Action(()=>{
progress .Value = 100;
status .Content = "更新完成";
}),null);
传统方法更新进度到ui(子线程):
private delegate void 子线程的代理(string MSG);//来一个代理,代理把子线程的方法传给主窗体线程
Thread pThread1 = new Thread(new ThreadStart(某方法));//某方法里面要更新ui,所以new一个线程让它运行,它要更新ui就调用,更新ui的方法(msg)
pThread1.IsBackground=true;
pThread1.Start();
private void 更新ui的方法(string msg)
{
if (this.InvokeRequired == false)//判断是否需要调用主窗体线程,若不需要
{
textBox1.AppendText(msg + "\r\n");
textBox1.ScrollToCaret();
}
else //若需要调用主窗体线程,就代理给主窗体线程呗!!!!
{
子线程的代理 代理 = new 子线程的代理(p增加到消息日志);
this.Invoke(代理, msg);//用主窗体来更新ui
}
}
线程池最多管理线程数量=“处理器数 * 250”。也就是说,如果您的机器为2个2核CPU,那么CLR线程池的容量默认上限便是1000
通过线程池创建的线程默认为后台线程,优先级默认为Normal。
ThreadPool.SetMinThreads(MaxThreadCount, 10);
//第一参数是设置线程池辅助线程,第二个值是设置异步I/O线程
//CLR线程池分为工作者线程(workerThreads)与I/O线程(completionPortThreads)两种。当你的程序是I/O密集型时,你应该将线程数向I/O偏移,如果你的程序是CPU密集型时,你应该将线程数向工作线程偏移。
// 设置最大空闲线程为500,就好像我告诉系统给我预先准备500个线程我来了就直接用,因为这样就不用现去申请了 //在线程池中每申请一个新的线程.NET Framework 会安排一个间隔时间,目前是半秒,以后的版本MS有可能会改
ThreadPool.QueueUserWorkItem(new WaitCallback(方法), 参数object); //参数可选
//判断线程池里的线程是否都执行完毕了
while (true)
{
Thread.Sleep(1000);//这句写着,主要是没必要循环那么多次。去掉也可以。
int maxWorkerThreads, workerThreads;
int portThreads;
ThreadPool.GetMaxThreads(out maxWorkerThreads, out portThreads);
ThreadPool.GetAvailableThreads(out workerThreads, out portThreads);
Console.WriteLine("maxWorkerThreads:"+maxWorkerThreads+ " workerThreads:"+workerThreads);
if (maxWorkerThreads - workerThreads == 0)
{
Console.WriteLine("结束了");
break;
}
}
//4 后台BackgroundWorker
开始
BGWorker.DoWork += 要后台的方法;
BGWorker.RunWorkerAsync(方法的参数);
void 要后台的方法(object sender, DoWorkEventArgs e);//e.Argument来获取方法的参数
把进度传递给UI:
BGWorker.WorkerReportsProgress = true;
BGWorker.ProgressChanged += 进度改变要干什么的函数;
bgWorker.ReportProgress(progressNum, "message");//更新进度
void 进度改变要干什么的函数(object sender, ProgressChangedEventArgs e);{this.progressBar.Value = e.ProgressPercentage;}
//如果有更多的信息需要传递,可以使用 e.UserState 传递一个自定义的类型。/这是一个 object 类型的对象,您可以通过它传递任何类型。
取消
允许取消:BGWorker.WorkerSupportsCancellation = true;
点击取消:BGWorker.CancelAsync();
点击取消后:在要后台的方法中判断点击了取消 if(BGWorker.CancellationPending){e.Cancel = true;return; }
后台操作完成后,反馈结果给用户
BGWorker.RunWorkerCompleted += 运行完成要执行的函数;
private void 运行完成要执行的函数(object sender, RunWorkerCompletedEventArgs e)
{
//DoWork 设置e.Result,RunWorkerCompleted里接收e.Result
//e.Error错误
if(e.Cancelled)
MessageBox.Show("被取消");
else
MessageBox.Show("完成");
}