C#多线程,基础知识很重要
本文通过介绍C#多线程的用法(基础玩法),附加介绍一下WinForm里边跨线程访问UI的方法
如图,就是这么一个简单的界面,每个按钮下面一个方法,分别设置文本框里边的内容,那么,开始吧!
先介绍一下WinForm的线程模型:WinForm 是通过调用Windows API 的GetMessage Or PeekMeeage来处理其他线程发送过来的消息,这些消息存储在系统的一个消息队列中,创建主界面的线程就是主线程(UI线程),UI线程负责消费该消息队列中的消息。
WinForm框架中有一个ISynchronizeInvoke接口,所有的UI元素都继承自该接口,接口中的InvokeRequired属性表示了当前线程是否是创建它的线程,接口中的BeginInvoke or Invoke 负责将消息发送到消息队列,这样UI线程就能够正确的访问它了。
那么,首先看代码片段一:里边就实现了将设置文本框内容的消息发送到了消息队列
private void SetMessage(string message)
{
if (this.txtMsg.InvokeRequired)
{
//BeginInvoke or Invoke 负责将消息发送到消息队列
this.txtMsg.BeginInvoke(new Action<string>((msg) =>
{
this.txtMsg.Text = msg;
}), message);
}
else
{
this.txtMsg.Text = message;
} }
代码片段二Thread:Thread可能是用的最多的了,也是最早的框架里边就有的。这种写法很简单,也很方便,需要提一下的就是IsBackground属性,IsBackground=true表示为后台线程,应用程序退出,哪怕任务没有执行完,也会退出;IsBackground=false表示为前台线程,默认为false,应用程序退出,只要任务还没有执行完,进程就不会结束。
private void btnThread_Click(object sender, EventArgs e)
{
Thread thread = new Thread(() =>
{
SetMessage("Thread 跨线程访问UI");
});
//IsBackground=true表示为后台线程 应用程序退出 哪怕任务没有执行完 也会退出
//IsBackground=false表示为后台线程 默认为false 应用程序退出 只要任务还没有执行完 进程就不会结束
thread.IsBackground = true;
thread.Start();
}
代码片段三ThreadPool:ThreadPool是微软为了避免开发人员,无节制的使用线程,而提供的一个线程管理类
private void btnThreadPool_Click(object sender, EventArgs e)
{
//线程池 是微软为了避免开发人员 无节制的使用线程 而提供的一个线程管理类
ThreadPool.QueueUserWorkItem((obj) =>
{
SetMessage("ThreadPool 跨线程访问UI");
}, null);
}
代码片段四Task:Task有很多的优势,也是后面高版本才推出来的,推荐使用。Task与Thread的区别就是:Task使用的是线程池中的线程,Task较之线程池的优势是:
1.Task支持取消,完成,失败通知等交互性操作
2.Task支持线程执行的先后次序
private void btnTask_Click(object sender, EventArgs e)
{
/* Task与Thread的区别就是:Task使用的是线程池中的线程
* Task较之线程池的优势是:
* 1.Task支持取消,完成,失败通知等交互性操作
* 2.Task支持线程执行的先后次序*/
Task.Factory.StartNew(() =>
{
SetMessage("Task 跨线程访问UI");
}); Task task = new Task(()=> {
SetMessage("Task 跨线程访问UI");
});
task.Start();
}
代码片段五BackgroundWorker:BackgroundWorker内部是通过线程池实现的,通过事件提供了跨线程访问UI的能力,这个做CS开发,是用的最多的,说白了,太好用。
//BackgroundWorker 内部是通过线程池实现的
//BackgroundWorker 通过事件提供了跨线程访问UI的能力
BackgroundWorker _bgw = new BackgroundWorker(); private void btnBackgroundWorker_Click(object sender, EventArgs e)
{
_bgw.WorkerReportsProgress = true;
_bgw.WorkerSupportsCancellation = true;
_bgw.DoWork += _bgw_DoWork; ;
_bgw.ProgressChanged += _bgw_ProgressChanged;
_bgw.RunWorkerCompleted += _bgw_RunWorkerCompleted; if (!_bgw.IsBusy)
{
_bgw.RunWorkerAsync();
}
} private void _bgw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
this.txtMsg.Text = "BackgroundWorker 跨线程访问UI";//注意这里是直接访问UI
} private void _bgw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
this.txtMsg.Text = e.UserState.ToString();//注意这里是直接访问UI
} private void _bgw_DoWork(object sender, DoWorkEventArgs e)
{
for (int i = ; i < ; i++)
{
Thread.Sleep();
_bgw.ReportProgress(i, $"{i}秒");
}
}
代码片段六SynchronizationContext:SynchronizationContext同步上下文在通讯中充当传输者的角色,实现功能就是一个线程和另外一个线程的通讯,这个在跨线程一次性要更新很多的UI控件的时候,非常的适用。
//SynchronizationContext 在通讯中充当传输者的角色,实现功能就是一个线程和另外一个线程的通讯
SynchronizationContext _syncContext; private void btnSynchronizationContext_Click(object sender, EventArgs e)
{
_syncContext = SynchronizationContext.Current;
Thread thread = new Thread(() =>
{
if (_syncContext != null)
{
SendOrPostCallback callBack = (obj) =>
{
//在某个子线程里 一次性要更新很多UI控件的时候 用这个方法 很nice
this.txtMsg.Text = "SynchronizationContext 跨线程访问UI";
};
_syncContext.Post(callBack, null);//异步
//_syncContext.Send(callBack, null);//同步
}
});
thread.IsBackground = true;
thread.Start();
}
合并之后的代码为:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms; namespace ThreadChapter
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
} private void btnThread_Click(object sender, EventArgs e)
{
Thread thread = new Thread(() =>
{
SetMessage("Thread 跨线程访问UI");
});
//IsBackground=true表示为后台线程 应用程序退出 哪怕任务没有执行完 也会退出
//IsBackground=false表示为后台线程 默认为false 应用程序退出 只要任务还没有执行完 进程就不会结束
thread.IsBackground = true;
thread.Start();
} /*
* WinForm 是通过调用Window API 的GetMessage Or PeekMeeage来处理其他线程发送过来的消息,
* 这些消息存储在系统的一个消息队列中,创建主界面的线程就是主线程(UI线程),UI线程负责处理该消息队列
*/ private void SetMessage(string message)
{
if (this.txtMsg.InvokeRequired)
{
//BeginInvoke or Invoke 负责将消息发送到消息队列
this.txtMsg.BeginInvoke(new Action<string>((msg) =>
{
this.txtMsg.Text = msg;
}), message);
}
else
{
this.txtMsg.Text = message;
} } private void btnThreadPool_Click(object sender, EventArgs e)
{
//线程池 是微软为了避免开发人员 无节制的使用线程 而提供的一个线程管理类
ThreadPool.QueueUserWorkItem((obj) =>
{
SetMessage("ThreadPool 跨线程访问UI");
}, null);
} private void btnTask_Click(object sender, EventArgs e)
{
/* Task与Thread的区别就是:Task使用的是线程池中的线程
* Task较之线程池的优势是:
* 1.Task支持取消,完成,失败通知等交互性操作
* 2.Task支持线程执行的先后次序*/
Task.Factory.StartNew(() =>
{
SetMessage("Task 跨线程访问UI");
});
} //BackgroundWorker 内部是通过线程池实现的
//BackgroundWorker 通过事件提供了跨线程访问UI的能力
BackgroundWorker _bgw = new BackgroundWorker(); private void btnBackgroundWorker_Click(object sender, EventArgs e)
{
_bgw.WorkerReportsProgress = true;
_bgw.WorkerSupportsCancellation = true;
_bgw.DoWork += _bgw_DoWork; ;
_bgw.ProgressChanged += _bgw_ProgressChanged;
_bgw.RunWorkerCompleted += _bgw_RunWorkerCompleted; if (!_bgw.IsBusy)
{
_bgw.RunWorkerAsync();
}
} private void _bgw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
this.txtMsg.Text = "BackgroundWorker 跨线程访问UI";//注意这里是直接访问UI
} private void _bgw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
this.txtMsg.Text = e.UserState.ToString();//注意这里是直接访问UI
} private void _bgw_DoWork(object sender, DoWorkEventArgs e)
{
for (int i = ; i < ; i++)
{
Thread.Sleep();
_bgw.ReportProgress(i, $"{i}秒");
}
} //SynchronizationContext 在通讯中充当传输者的角色,实现功能就是一个线程和另外一个线程的通讯
SynchronizationContext _syncContext; private void btnSynchronizationContext_Click(object sender, EventArgs e)
{
_syncContext = SynchronizationContext.Current;
Thread thread = new Thread(() =>
{
if (_syncContext != null)
{
SendOrPostCallback callBack = (obj) =>
{
//在某个子线程里 一次性要更新很多UI控件的时候 用这个方法 很nice
this.txtMsg.Text = "SynchronizationContext 跨线程访问UI";
};
_syncContext.Post(callBack, null);//异步
//_syncContext.Send(callBack, null);//同步
}
});
thread.IsBackground = true;
thread.Start();
}
}
}
C#多线程,基础知识很重要的更多相关文章
- Java 多线程——基础知识
java 多线程 目录: Java 多线程——基础知识 Java 多线程 —— synchronized关键字 java 多线程——一个定时调度的例子 java 多线程——quartz 定时调度的例子 ...
- Java多线程基础知识笔记(持续更新)
多线程基础知识笔记 一.线程 1.基本概念 程序(program):是为完成特定任务.用某种语言编写的一组指令的集合.即指一段静态的代码,静态对象. 进程(process):是程序的一次执行过程,或是 ...
- JAVA多线程基础知识(一)
一. 基础知识 要了解多线程首先要知道一些必要的概念,如进程,线程等等.开发多线程的程序有利于充分的利用系统资源(CPU资源),使你的程序执行的更快,响应更及时. 1. 进程,一般是指程序或者任务的执 ...
- Java基础知识强化之多线程笔记01:多线程基础知识(详见Android(java)笔记61~76)
1. 基础知识: Android(java)学习笔记61:多线程程序的引入 ~ Android(java)学习笔记76:多线程-定时器概述和使用
- Java多线程基础知识总结
2016-07-18 15:40:51 Java 多线程基础 1. 线程和进程 1.1 进程的概念 进程是表示资源分配的基本单位,又是调度运行的基本单位.例如,用户运行自己的程序,系统就创建一个进程, ...
- C#中的多线程 - 基础知识
原文:http://www.albahari.com/threading/ 文章来源:http://blog.gkarch.com/threading/part1.html 1简介及概念 C# 支持通 ...
- C#中的多线程 - 基础知识 z
原文:http://www.albahari.com/threading/ 专题:C#中的多线程 1简介及概念Permalink C# 支持通过多线程并行执行代码,线程有其独立的执行路径,能够与其它线 ...
- Java多线程基础知识例子
一.管理 1.创建线程 Thread public class Main { public static void main(String[] args) { MyThread myThread = ...
- Java多线程基础知识篇
这篇是Java多线程基本用法的一个总结. 本篇文章会从一下几个方面来说明Java多线程的基本用法: 如何使用多线程 如何得到多线程的一些信息 如何停止线程 如何暂停线程 线程的一些其他用法 所有的代码 ...
随机推荐
- 【ZJOI2017 Round1练习&BZOJ5354】D7T3 room(DP)
题意: 思路: 写了两种版本 考场版本 ..,..]of longint; t:..,..]of longint; n,m,i,j,k,oo,ans,d1:longint; function min( ...
- 关于jquery stopPropagation()阻止冒泡事件
我们经常会遇到点击两个或者多个重叠的层事件的时候,往往点击最里的的一层会接连触发外面的点击事件.这时候就需要用到stopPropagation事件即阻止冒泡事件html代码如下<!DOCTYPE ...
- IntentService用于服务中开启子线程的自动关闭
package com.pingyijinren.test; import android.app.IntentService; import android.content.Intent; impo ...
- HDU1166 线段树裸题 区间求和
敌兵布阵 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submis ...
- java服务器图片压缩的几种方式及效率比较
以下是测试了三种图片压缩方式,通过测试发现使用jdk的ImageIO压缩时间更短,使用Google的thumbnailator更简单,但是thumbnailator在GitHub上的源码已经停止维护了 ...
- 洛谷——P2866 [USACO06NOV]糟糕的一天Bad Hair Day
https://www.luogu.org/problem/show?pid=2866 题目描述 Some of Farmer John's N cows (1 ≤ N ≤ 80,000) are h ...
- 洛谷 P4181 [USACO18JAN]Rental Service
P4181 [USACO18JAN]Rental Service 题意翻译 farmer john有N(1≤N≤100,000)头牛,他想赚跟多的钱,所以他准备买牛奶和出租牛.有M(1≤M≤100,0 ...
- JSP的隐藏对象
以下内容引用自http://wiki.jikexueyuan.com/project/jsp/implicit-objects.html: JSP隐式对象是Java对象,JSP容器使隐式对象在每一个页 ...
- C#代码读写XML
<1> 创建XML文档 using System; using System.Collections.Generic; using System.Linq; using System.Te ...
- vux 实现多栏滚动
1.PopupPicker 组件 <!-- vux-ui --> <template> <div> <!-- 标题栏 --> <x-header ...