多线程初始
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 _01_多线程初始
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
//访问当前代码执行的线程
Thread thread =Thread.CurrentThread;
thread.Name = "主";
}
private void tzm()
{
Console.WriteLine($"当前任务执行在{Thread.CurrentThread.Name}线程");
Thread.Sleep(5000);//暂停 暂停5秒,模拟挑芝麻的耗时事件
MessageBox.Show("芝麻调好了,滚!!!!!");
}
private void button1_Click(object sender, EventArgs e)
{
tzm();
}
private void button2_Click(object sender, EventArgs e)
{
MessageBox.Show("给");
}
private void button3_Click(object sender, EventArgs e)
{
//用分线程执行耗时任务
//1.创建一个委托,用于告诉线程要干什么工作
ThreadStart threadStart = new ThreadStart(tzm);
//2.创建一个线程,并告知其任务
Thread t =new Thread(threadStart);
t.Name = "分";
//3.启动线程,开始执行任务
t.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 _02_多线程案例
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
Thread.CurrentThread.Name = "主线程";
}
void Calc()
{
Console.WriteLine(Thread.CurrentThread.Name+"开始执行");
int sum= 0;
for (int i = 0; i <=300; i++)
{
Thread.Sleep(1);
sum += i;
}
//需要使用启动并调试查看错误
//System.InvalidOperationException:“线程间操作无效: 从不是创建控件“label1”的线程访问它。”
//因为lable1空间是由主线程创建的,分线程不能去操作他
//分线程不能操作UI(窗体,控件)
label1.Text = $"1-300之间的数字的和是{sum}";
}
private void button1_Click(object sender, EventArgs e)
{
Calc();
}
private void button2_Click(object sender, EventArgs e)
{
ThreadStart threadStart = new ThreadStart(Calc);
Thread thread =new Thread(threadStart);
thread.Name = "分线程";
thread.Start();
}
}
}
线程通讯_分传主
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace _03_线程通讯_分传主
{
public partial class Form1 : Form
{
//1.定义一个变量存储主线程的执行期上下文
SynchronizationContext mainContent;
public Form1()
{
InitializeComponent();
Thread.CurrentThread.Name = "主线程";
}
void Fn()
{
Console.WriteLine(Thread.CurrentThread.Name);
Thread.Sleep(3000);
//4.分线程调用方法,给主线程传递数据
mainContent.Post(Abc, "我是分线程计算的结果");
}
private void button1_Click(object sender, EventArgs e)
{
//2.设置变量存储当前主线程的执行期上下文
mainContent = SynchronizationContext.Current;
//ThreadStart threadStart = new ThreadStart(Fn);
// Thread thread = new Thread(threadStart);
//thread.Name = "分线程";
//thread.Start();
//启动分线程执行耗时任务
//3.启动分线程让他执行耗时任务
new Thread(new ThreadStart(Fn)) { Name = "分线程" }.Start();
}
//5.定义函数,当分线程发送数据的时候执行
void Abc(object o)
{
//函数的参数就是第4步调用函数的时候传递的第二个参数
Console.WriteLine(o);
Console.WriteLine("Abc"+Thread.CurrentThread.Name);
//主线程
label1.Text=o.ToString();
}
}
}
线程通讯_主传分
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 _04_线程通讯_主传分
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Calc(object obj)
{
Console.WriteLine("obj:"+obj);
int sum = 0;
for (int i = 0; i < Convert.ToInt32(obj); i++)
{
Thread.Sleep(1);
sum += i;
}
//sum 和 需要显示在ui界面上
//在分线程中操作ui页面
//参数是一个委托类型
Invoke(new Action(() =>
{
label1.Text = $"1-{obj}的和为:{sum}";
}));
}
private void button1_Click(object sender, EventArgs e)
{
//主线程
// Calc();
// ThreadStart 没有参数的函数类型
//1.创建接收参数的委托
//ParameterizedThreadStart ts = new ParameterizedThreadStart(Calc);
2.创建线程
//Thread thread = new Thread(ts);
//thread.Name = "分线程";
3.执行线程
//thread.Start(100);//调用Start方法的时候传递参数即可
//简写形式:
//注意:如果分线程执行的任务方法要接收参数,只能接收object类型,调用Start方法的时候传递参数即可
new Thread(Calc).Start(100);
}
private void button2_Click(object sender, EventArgs e)
{
new Thread(Calc).Start(200);
}
private void button3_Click(object sender, EventArgs e)
{
new Thread(Calc).Start(300);
}
}
}
关闭线程
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace _05_关闭线程
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
void Fn()
{
Thread.Sleep(1000);
Console.WriteLine("1秒过去了");
Thread.Sleep(1000);
Console.WriteLine("2秒过去了");
Thread.Sleep(1000);
Console.WriteLine("3秒过去了");
Thread.Sleep(1000);
Console.WriteLine("4秒过去了");
}
Thread thread;
private void button1_Click(object sender, EventArgs e)
{
//Start() //开启线程
thread= new Thread(Fn);
thread.Start();
}
private void button3_Click(object sender, EventArgs e)
{
// Abort() 销毁线程
//线程将会在他任务执行完成之后被自动销毁,也可以手动销毁
thread.Abort();
}
}
}
线程锁
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 _06_线程锁
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
new Thread(Fn1).Start();
new Thread(Fn2).Start();
new Thread(Fn3).Start();
}
void Fn1()
{
Thread.Sleep(100);
Invoke(new Action<string>(changUi), "我是我1号线程修改的内容");
}
void Fn2()
{
Thread.Sleep(100);
Invoke(new Action<string>(changUi), "我是我2号线程修改的内容");
}
void Fn3()
{
Thread.Sleep(100);
Invoke(new Action<string>(changUi), "我是我3号线程修改的内容");
}
void changUi(Object value)
{
label1.Text=value.ToString();
}
//每次点击按钮lable都显示不同的文本,因为不同的线程执行的先后顺序不一定相同
//执行完成的时刻也不一定相同,因此我们无法掌控某个线程执行的实际,
// 上面是哪个线程谁都可以先执行完毕,也有可能同时执行完毕
//1.创建一个锁(锁一般是一个引用类型)
private static readonly object key =new object();
//多个线程操作一个变量,导致我们的判断无法进行限制
int apple;
private void button2_Click(object sender, EventArgs e)
{
apple = 1;
new Thread(WuyifanEat).Start();
new Thread(LuozhxiangEat).Start();
}
void WuyifanEat()
{
Console.WriteLine("吴亦凡吃苹果,去看看还有没有");
//2.使用锁将代码锁起来,(互斥的,相互排斥的锁,当锁关闭的时候,另一个位置无法进入)
lock (key)
{
if (apple <= 0)
{
Console.WriteLine("吴亦凡:没有苹果了,不吃了");
return;
}
Thread.Sleep(100);
apple--;
}
Console.WriteLine($"吴亦凡吃完了,现在还剩{apple}个苹果");
Thread.Sleep(2000);
Console.WriteLine("吴亦凡吃完了");
}
void LuozhxiangEat()
{
Console.WriteLine("罗志祥吃苹果,去看看还有没有");
lock (key)
{
if (apple <= 0)
{
Console.WriteLine("罗志祥:没有苹果了,不吃了");
return;
}
Thread.Sleep(100);
apple--;
}
Console.WriteLine($"罗志祥吃完了,现在还剩{apple}个苹果");
Thread.Sleep(2000);
Console.WriteLine("罗志祥吃完了");
}
}
}
使用锁的注意事项
1、lock锁括号中使用的锁必须是引用类型,string除外
2、推荐锁使用静态的、私有的、只读的对象
3、我们的锁一定要保证不会被对象的外部所操作才有意义,否则就有可能被手动上锁造成死锁
注意:不要使用字符串当锁,因为这个操作很危险,因为字符串被公共语言运行库(CLR)“暂留”。这意味着整个程序中任何给定字符串都只有一个实例,就是这同一个对象表示了所有运行的应用程序域的所有线程中的该文本。因此,只要在应用程序进程中的任何位置处具有相同内容的字符串上放置了锁,就将锁定应用程序中该字符串的所有实例。通常,最好避免锁定 public 类型或锁定不受应用程序控制的对象实例。
例如,如果该实例可以被公开访问,则 lock(this) 可能会有问题,因为不受控制的代码也可能会锁定该对象。这可能导致死锁,即两个或更多个线程等待释放同一对象。
出于同样的原因,锁定公共数据类型(相比于对象)也可能导致问题。而且lock(this)只对当前对象有效,如果多个对象之间就达不到同步的效果。
lock(typeof(Class))与锁定字符串一样,范围太广了。