總結(jié):視頻中對于多線程講的非常透徹,從線程基礎概念—>.net不同版本出現(xiàn)的線程方法—>多線程常出現(xiàn)問題—>雙色球項目實踐,每個知識點都有代碼實操,受益匪淺。附上學習筆記和實操代碼。
視頻
一、線程、進程概念及優(yōu)缺點
線程:程序執(zhí)行的最小單位,任何操作都是由線程完成的,使用同步時,資源一直被此線程占用,所以其他界面干不了,會出現(xiàn)卡界面的現(xiàn)象。
1啟動不可控制、2結(jié)束不可控
一個耗時(i++)、耗資源(thread.sleep)的方法
二、四種異步等待方式
1.異步控制等待-callback回調(diào)
action執(zhí)行完將asyncResult、"nimen"當成參數(shù)傳給callback
2.異步控制等待-asyncResult.IsCompleted
3.異步控制等待WaitOne()-信號量
4.異步控制等待endinvoke-拿到異步函數(shù)的返回值
5.視頻第1節(jié)課代碼
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 multithread
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Console.WriteLine($"[------------主線程start: 線程號:({Thread.CurrentThread.ManagedThreadId.ToString("00")})---{System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}-----]");
/*1調(diào)用委托
{
Action<string> action = this.dosomething;
action.Invoke("AA");//同步調(diào)用委托
action("BB");//同步調(diào)用委托
action.BeginInvoke("cc", null, null);//異步調(diào)用委托
}
/*2異步-不可控
{
Action<string> action = this.dosomething;
for (int i = 0; i < 5; i++)
{
string name = string.Format($"btn_click_{i}");
action.BeginInvoke(name, null, null);//異步調(diào)用委托
}
}*/
/*3.異步不可控
{
Action<string> action = this.dosomething;
action.BeginInvoke("cc", null, null);
Console.WriteLine($"[------------到這里計算完成: 線程號:({Thread.CurrentThread.ManagedThreadId.ToString("00")})---{System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}-----]");
}*/
/*4.異步等待1-回調(diào)
{
Action<string> action = this.dosomething;
AsyncCallback callback = new AsyncCallback(i => Console.WriteLine($"[------------到這里計算完成: 線程號:({Thread.CurrentThread.ManagedThreadId.ToString("00")})---{System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}-----]"));
//簡單寫法
AsyncCallback callback1 = i => Console.WriteLine($"[------------到這里計算完成: 線程號:({Thread.CurrentThread.ManagedThreadId.ToString("00")})---{System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}-----]");
action.BeginInvoke("cc", callback, null);
}*/
/*5.異步等待1-回調(diào)解析(action執(zhí)行完將asyncResult、"nimen"當成參數(shù)傳給callback)-不卡界面
{
Action<string> action = this.dosomething;
IAsyncResult asyncResult = null;
AsyncCallback callback = i =>
{
Console.WriteLine(object.ReferenceEquals(asyncResult , i));
Console.WriteLine(i.AsyncState);
Console.WriteLine($"[------------到這里計算完成: 線程號:({Thread.CurrentThread.ManagedThreadId.ToString("00")})---{System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}-----]");
};
asyncResult = action.BeginInvoke("cc", callback, "nimen");
}
*/
/*6.異步等待2 asyncResult.IsCompleted-回調(diào)解析-while函數(shù)卡界面
{
Action<string> action = this.dosomething;
IAsyncResult asyncResult = null;
AsyncCallback callback = i =>
{
Console.WriteLine(object.ReferenceEquals(asyncResult, i));
Console.WriteLine(i.AsyncState);
Console.WriteLine($"[------------到這里計算完成: 線程號:({Thread.CurrentThread.ManagedThreadId.ToString("00")})---{System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}-----]");
};
asyncResult = action.BeginInvoke("cc", callback, "nimen");
int a = 0;
while (!asyncResult.IsCompleted)
{
if (a < 10)
{
Console.WriteLine($"文件上傳{a++ * 10}%..");
Console.WriteLine($"線程號:({Thread.CurrentThread.ManagedThreadId.ToString("00")})---{System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}");
}
else
{
Console.WriteLine($"文件上傳99.9%..");
}
Thread.Sleep(200);
}
}*/
/*7.異步等待3-WaitOne()-信號量3
{
Action<string> action = this.dosomething;
IAsyncResult asyncResult = action.BeginInvoke("cc", null, null);
Console.WriteLine("dosomething");
Console.WriteLine("dosomething");
asyncResult.AsyncWaitHandle.WaitOne();//等待異步任務完成后,才打印計算完成
asyncResult.AsyncWaitHandle.WaitOne(2000);//限時等待
Console.WriteLine($"[------------到這里計算完成: 線程號:({Thread.CurrentThread.ManagedThreadId.ToString("00")})---{System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}-----]");
}*/
/*.8異步等待4endinvoke-拿到委托函數(shù)的返回值
{
Action<string> action = this.dosomething;
Func<int> func = () =>
{
Thread.Sleep(2000);
return DateTime.Now.Day;
};
Console.WriteLine($"func.Invoke()={ func.Invoke()}");
IAsyncResult asyncResult=func.BeginInvoke(r =>
{
Console.WriteLine(r.AsyncState);
}, "nimen");
Console.WriteLine($"func.EndInvoke={ func.EndInvoke(asyncResult)}");
Console.WriteLine($"[------------到這里計算完成: 線程號:({Thread.CurrentThread.ManagedThreadId.ToString("00")})---{System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}-----]");
}*/
Console.WriteLine($"[------------主線程end: 線程號:({Thread.CurrentThread.ManagedThreadId.ToString("00")})---{System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}-----]");
}
private void dosomething(string name)
{
Console.WriteLine($"[****Dosomething {name} start: 線程號:({Thread.CurrentThread.ManagedThreadId.ToString("00")})---{System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}*******]");
long result = 0;
for(int i =0; i < 10000000; i++)
{
result += i;
}
Thread.Sleep(2000);
Console.WriteLine($"[****Dosomething {name} end: 線程號:({Thread.CurrentThread.ManagedThreadId.ToString("00")})---{System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}{result}*******]");
}
}
}
三、.net1.0基礎版的thread對象
1.線程啟動
{
//Action<string> action = this.dosomething;
//IAsyncResult asyncResult = action.BeginInvoke("cc", null, null);
//Action action1 =()=> this.dosomething("CC");
//1.線程啟動 thread.Start();
ThreadStart threadStart = () => this.dosomething("cc");
Thread thread = new Thread(threadStart);
thread.Start();
//2.線等待程thread.Join();
thread.Join(500);//卡主線程
Console.WriteLine($"等待500ms");
thread.Join();
while (thread.ThreadState != ThreadState.Stopped)
{
Thread.Sleep(100);//cpu時間片交出去干其他的事,但是內(nèi)存還是占用
}
2.thread.join()\thread.sleep()\thread.IsBackfround
thread.join(500),是其他人線程等他500ms,此時有兩個線程在工程, 一個在等待500ms,一個是自己在運行
thread.sleep(500),是自己線程自己將cpu時間片交出去干其他的事,但是內(nèi)存還是占用,休眠500ms
前臺線程,當軟件閃退時,會吐出日志
四、net 2.0 threadpool
1.線程啟動、設置線程池最大線程數(shù)
2.manualResetEvent.WaitOne()異步控制等待
{
ManualResetEvent manualResetEvent = new ManualResetEvent(false);
ThreadPool.QueueUserWorkItem(t =>
{
this.dosomething("cc");
manualResetEvent.Set();
});//接收一個沒有返回值的委托
manualResetEvent.WaitOne();
Console.WriteLine($"等待ThreadPool.QueueUserWorkItem執(zhí)行完再執(zhí)行");
}
waitone()風險,無線程可用會卡住
3.手寫異步回調(diào)函數(shù)
4.帶返回值的委托異步調(diào)用(法語結(jié)構(gòu)待學習)
五、.net3.0 task
1.task線程啟動
2.waitall、waitany都會卡主線程卡界面
waitall、waitany應用場景
3.task.whenall.continuewith()
首先task.whenall不卡主界面,快快的結(jié)束了btn_task_click是主線程任務
其次continuewith() ,當tasklist中線程執(zhí)行后并滿足條件時(all\any),直接順序執(zhí)行下面的委托,類似回調(diào)如“得意的笑”
4.taskfactory.continuewith()
5.設計最多只有11個線程在工作
6.taskfactory檢測到哪個線程結(jié)束后,返回線程標識
7.task多次嵌套實現(xiàn)不卡主線程
8.兩個waitall按順序執(zhí)行
如果有兩個waitall需要執(zhí)行但他們在不同線程中,但是又要保證這兩次waitall的順序,解決辦法,將第一個waitall加到tasklist中,然后讓第二個task的waitall來判斷
9.thread.sleep()卡線程 task.delay()不卡線程
10.task線程完成標識
六、.net4.5 parallel
1.parallel啟動多線程
2.parallel線程停止
七、threadcore
1.異常處理
主線程出現(xiàn)異常沒人管理會導致程序崩潰
try {
TaskFactory taskFactory = new TaskFactory();
List < Task > tasklist = new List<Task>();
//異常處理
for(int i =0;i<20; i++)
{
string name = string.Format($"btn_click_{i}");
Action<object> act = t =>
{
try
{
Thread.Sleep(2000);
if (t.ToString().Equals("btn_click_11"))
{
throw new Exception(string.Format($"{t}執(zhí)行失敗"));
}
if (t.ToString().Equals("btn_click_12"))
{
throw new Exception(string.Format($"{t}執(zhí)行失敗"));
}
Console.WriteLine("{0}執(zhí)行成功", t);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
};
tasklist.Add(taskFactory.StartNew(act, name));
};
Task.WaitAll(tasklist.ToArray());
}
catch (AggregateException aex)
{
foreach(var item in aex.InnerExceptions)
{
Console.WriteLine(item.Message);
}
}
catch(Exception ex)
{
Console.WriteLine(ex.Message);
}
2.線程取消
tasklist.Add(taskFactory.StartNew(act, name))時,
tasklist.Add(taskFactory.StartNew(act, name,cts.Token))時,
try {
TaskFactory taskFactory = new TaskFactory();
List < Task > tasklist = new List<Task>();
CancellationTokenSource cts = new CancellationTokenSource();
for(int i =0;i<40; i++)
{
string name = string.Format($"btn_click_{i}");
Action<object> act = t =>
{
try
{
/*
if (cts.IsCancellationRequested)
{
Console.WriteLine("{0}取消一個任務的執(zhí)行",t);
}*/
Thread.Sleep(2000);
if (t.ToString().Equals("btn_click_11"))
{
throw new Exception(string.Format($"{t}執(zhí)行失敗"));
}
if (t.ToString().Equals("btn_click_12"))
{
throw new Exception(string.Format($"{t}執(zhí)行失敗"));
}
/*
else
{
Console.WriteLine("{0}執(zhí)行成功", t);
}*/
if (cts.IsCancellationRequested)
{
Console.WriteLine("{0}放棄執(zhí)行", t);
return;
}
else
{
Console.WriteLine("{0}執(zhí)行成功", t);
}
}
catch (Exception ex)
{
cts.Cancel();
Console.WriteLine(ex.Message);
}
};
tasklist.Add(taskFactory.StartNew(act, name,cts.Token));
}
Task.WaitAll(tasklist.ToArray());
}
catch (AggregateException aex)
{
foreach(var item in aex.InnerExceptions)
{
Console.WriteLine(item.Message);
}
}
catch(Exception ex)
{
Console.WriteLine(ex.Message);
}
3.多線程臨時變量
4.線程安全lock(lock鎖的是引用)
4.1線程安全問題
4.2線程共有變量存在線程安全問題
4.3lock鎖原理
只有一個線程可以進去,沒有并發(fā) ,解決問題但犧牲性能
建議使用微軟定義的鎖
private static readonly object btn_click_lock = new object();//引用型變量
private int TotalCount = 0;
private List<int> IntList = new List<int>();
private void button1_Click(object sender, EventArgs e)
{
Console.WriteLine($"[------------主線程start: 線程號:({Thread.CurrentThread.ManagedThreadId.ToString("00")})---{System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}-----]");
TaskFactory taskFactory = new TaskFactory();
//private static readonly object btn_click_lock = new object();
List<Task> tasklist = new List<Task>();
for (int i = 0; i< 10000; i++)
{
int newI = i;
/*
//非多線程
this.TotalCount += 1;
this.IntList.Add(newI);*/
//多線程
tasklist.Add(taskFactory.StartNew(() =>
{
// int m = 3 + 2;
lock (btn_click_lock)
{
this.TotalCount += 1;
this.IntList.Add(newI);
}
}));
}
Task.WaitAll(tasklist.ToArray());
Console.WriteLine(this.TotalCount);
Console.WriteLine(this.IntList.Count());
Console.WriteLine($"[------------主線程end: 線程號:({Thread.CurrentThread.ManagedThreadId.ToString("00")})---{System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}-----]");
}
八、.net.0 await/async
1.await原理
await后的代碼相當于回調(diào),只不過不是自己寫的,是編譯器狀態(tài)機自帶的。
回調(diào)方法continuewith是子線程完成的,但await不僅僅是回調(diào)(可子線程可主線程,計算機分配),所以他們又有所不同
1.1小代碼測試原理
2.帶與不帶返回值的async方法
2.1只有asynic
2.2asynic\await成對出現(xiàn)
await 后面是要跟帶有返回值的方法
在定義方法時,有了async和await套裝后,盡管方法沒有return,但此方法也可看成是帶返回值的
不使用返回值
使用返回值
2.3t.Wait()與await t區(qū)別
2.4await反編譯-相當于狀態(tài)機
3.此知識點代碼
private void button1_Click(object sender, EventArgs e)
{
testshow();
}
public static void testshow()
{
test();
}
private async static Task test()
{
Console.WriteLine($"當前主線程id={Thread.CurrentThread.ManagedThreadId.ToString("00")}---{System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}");
{
//NoReturnNoAwait();
NoReturn();
for (int i = 0; i < 10; i++)
{
Thread.Sleep(300);
Console.WriteLine($"main thread task managedthreadid={Thread.CurrentThread.ManagedThreadId.ToString("00")}---{System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}--i={i}");
}
}
}
private static async void NoReturn()
{
//主線程執(zhí)行
Console.WriteLine($"NoReturn sleep before await ,threadid={Thread.CurrentThread.ManagedThreadId.ToString("00")}---{System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}");
TaskFactory taskFactory = new TaskFactory();
Task task = taskFactory.StartNew(() =>
{
Console.WriteLine($"NoReturn sleep before ,threadid={Thread.CurrentThread.ManagedThreadId.ToString("00")}---{System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}");
Thread.Sleep(300);
Console.WriteLine($"NoReturn sleep after ,threadid={Thread.CurrentThread.ManagedThreadId.ToString("00")}---{System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}");
});
await task;
Console.WriteLine($"NoReturn sleep after await ,threadid={Thread.CurrentThread.ManagedThreadId.ToString("00")}---{System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}");
}
private static async void NoReturnNoAwait()
{
//主線程執(zhí)行
Console.WriteLine($"NoReturnNoAwait sleep before task ,threadid={Thread.CurrentThread.ManagedThreadId.ToString("00")}---{System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}");
Task task = Task.Run(() =>
{
Console.WriteLine($"NoReturnNoAwait sleep before ,threadid={Thread.CurrentThread.ManagedThreadId.ToString("00")}---{System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}");
Thread.Sleep(300);
Console.WriteLine($"NoReturnNoAwait sleep after ,threadid={Thread.CurrentThread.ManagedThreadId.ToString("00")}---{System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}");
});
Console.WriteLine($"NoReturnNoAwait sleep after task ,threadid={Thread.CurrentThread.ManagedThreadId.ToString("00")}---{System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}");
}
九、雙色球項目
1.代碼
知識點
1.7個獨立任務,要多線程計算,啟動7個線程后,線程內(nèi)存while一直計算
2.子線程不能更新界面,所以要this.Updatelbl(lbl, sNumber)實現(xiàn)
3.通過while (this.isgoon)從外面終止7個線程
4.通過lock (llock)對7個子線程進行加鎖,避免7個線程同一時刻的值是一樣的
5.子線程等待,更新界面 if (!this.isexsit(“00”) && !this.blue.Text.Equals(“00”))
6.所有子線程都執(zhí)行完后回調(diào)taskFactory.ContinueWhenAll(this.tasklist.ToArray(), t => this.ShowResult() );//文章來源:http://www.zghlxwxcb.cn/news/detail-681454.html
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 雙色球
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
this.start.Enabled = true;
this.stop.Enabled = false;
}
private string[] rednums = {
"01","02","03","04","05","06","07","08","09","10",
"11","12","13","14","15","16","17","18","19","20",
"21","22","23","24","25","26","27","28","29","30",
"31","32","33"
};
private string[] bluenums = {
"01","02","03","04","05","06","07","08","09","10",
"11","12","13","14","15","16"
};
private static readonly object llock =new object();
private bool isgoon = true;
private List<Task> tasklist = new List<Task>();
private void start_Click(object sender, EventArgs e)
{
try
{
this.start.Text = "運行ing";
this.start.Enabled = false;
this.isgoon = true;
this.tasklist = new List<Task>();
this.blue.Text = "00";
this.label1.Text = "00";
this.label2.Text = "00";
this.label3.Text = "00";
this.label4.Text = "00";
this.label5.Text = "00";
this.label6.Text = "00";
Console.WriteLine(new Random().Next(0, 15));
Console.WriteLine(new Random().Next(0, 15));
Console.WriteLine(new Random().Next(0, 15));
Console.WriteLine(new Random().Next(0, 15));
Thread.Sleep(1000);
TaskFactory taskFactory = new TaskFactory();
foreach(var control in this.groupBox1.Controls)
{
if (control is Label)//標簽中
{
Label lbl = (Label)control;
if (lbl.Name.Contains("blue")) //blue
{
tasklist.Add( taskFactory.StartNew(() =>
{
while (this.isgoon)
{
int indexNum1 = Getrandombnumlong(0, bluenums.Length);
string sNumber = this.bluenums[indexNum1];
// lbl.Text = sNumber;
this.Updatelbl(lbl, sNumber);
}
}));
}
else//red
{
tasklist.Add( taskFactory.StartNew(() =>
{
while (this.isgoon)
{
int indexNum1 = Getrandombnumlong(0, this.rednums.Length);
string sNumber = this.rednums[indexNum1];
// lbl.Text = sNumber;
lock (llock)
{
if (this.isexsit(sNumber))//加鎖防止random出現(xiàn)一樣的值
{
continue;//重復數(shù)據(jù)時放棄更新
}
this.Updatelbl(lbl, sNumber);//7個線程訪問的是內(nèi)存中同一個string sNumber,加鎖防止取到的值是重復的,
}
}
}));
}
}
}
//Thread.Sleep(3000);//直接等3000ms讓stop開關(guān)enable,不靠譜,有可能有的線程因為數(shù)據(jù)重復,text沒有更新
//this.stop.Enabled = true;
/*
while (true)
{
Thread.Sleep(1000);
if (!this.isexsit("00") && !this.blue.Text.Equals("00"))
{
this.stop.Enabled = true;
break;
}
}*/
Task.Run(()=> {
while (true)
{
Thread.Sleep(1000);
if (!this.isexsit("00") && !this.blue.Text.Equals("00"))
{
this.Invoke(new Action(()=>{
this.stop.Enabled = true;//子線程操控不了主線程控件,需要主線程來完成
}));
break;
}
}
});
taskFactory.ContinueWhenAll(this.tasklist.ToArray(), t => this.ShowResult() );//所有子線程都執(zhí)行完
}
catch(Exception ex)
{
Console.WriteLine("雙色球啟動出現(xiàn)異常:{0}",ex.Message);
}
}
private void stop_Click(object sender, EventArgs e)
{
this.start.Enabled = true;
this.stop.Enabled = false;
this.isgoon = false;
//Task.WaitAll(this.tasklist.ToArray());//主線程等著全部任務完成,子任務還需要主線程干活更新label,所以又是死鎖
//this.ShowResult();
}
private void ShowResult()
{
MessageBox.Show(string.Format("本期雙色球為:{0} {1} {2} {3} {4} {5} 藍球{6}"
, this.label1.Text
, this.label2.Text
, this.label3.Text
, this.label4.Text
, this.label5.Text
, this.label6.Text
, this.blue.Text ));
}
//更新界面
private void Updatelbl(Label lbl ,string text)
{
if (lbl.InvokeRequired)
{
//這里的this指的是winform窗體主UI線程,讓UI線程去更新text值
this.Invoke(new Action(()=>{
//if (this.isgoon) //不延遲,點了就不更新
// {
lbl.Text = text;
Console.WriteLine($"當前update線程id{Thread.CurrentThread.ManagedThreadId}");
// }
}));
}
else
{
lbl.Text = text;
}
}
//驗證標簽中的text是否有相同的值
private bool isexsit(string snumber)
{
foreach (var control in this.groupBox1.Controls)
{
if (control is Label)//標簽中的
{
Label lbl = (Label)control;
if (lbl.Name.Contains("label"))
{
if (lbl.Text.Equals(snumber))
{
return true;
}
}
}
}
return false;
}
public int Getrandombnumlong(int min , int max)
{
int indexNum = new Random().Next(min, max);
Thread.Sleep(1000);
return indexNum;
}
}
}
文章來源地址http://www.zghlxwxcb.cn/news/detail-681454.html
十、知識點代碼匯總
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace multithread
{
public class Class1
{
private void dosomething(string name)
{
Console.WriteLine($"[****Dosomething {name} start: 線程號:({Thread.CurrentThread.ManagedThreadId.ToString("00")})---{System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}*******]");
}
//
//Console.WriteLine($"[------------到這里計算完成: 線程號:({Thread.CurrentThread.ManagedThreadId.ToString("00")})---{System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}-----]");
private void mainpoints() {
//1委托調(diào)用
Action<string> action = this.dosomething;//委托帶參數(shù)
Action action1 = () => this.dosomething("CC");//委托不帶參數(shù)
action.Invoke("AA");//同步調(diào)用委托
action("BB");//同步調(diào)用委托
action.BeginInvoke("cc", null, null);//異步調(diào)用委托
for (int i = 0; i < 5; i++)
{
string name = string.Format($"btn_click_{i}");
action.BeginInvoke(name, null, null);//異步多線程
}
List<Task> tasklist = new List<Task>();
TaskFactory taskFactory = new TaskFactory();
string name1 = string.Format($"btn_click");
CancellationTokenSource cts = new CancellationTokenSource();
Action<object> act = t =>
{
if (t.ToString().Equals("btn_click_11"))
{
throw new Exception(string.Format($"{t}執(zhí)行失敗"));
}
};
tasklist.Add(taskFactory.StartNew(act, name1, cts.Token));
//2.委托執(zhí)行完后進行回調(diào)
//標準寫法
AsyncCallback callback = new AsyncCallback(i => Console.WriteLine($"[------------到這里計算完成: 線程號:({Thread.CurrentThread.ManagedThreadId.ToString("00")})---{System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}-----]"));
//簡單寫法
AsyncCallback callback1 = i =>
{
Console.WriteLine($"[------------到這里計算完成: 線程號:({Thread.CurrentThread.ManagedThreadId.ToString("00")})---{System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}-----]");
};
action.BeginInvoke("cc", callback, null);
//回調(diào)1 -異步action執(zhí)行完才會執(zhí)行回調(diào)-action.BeginInvoke("cc", callback, "nimen")-1
IAsyncResult asyncResult = null;
asyncResult = action.BeginInvoke("cc", callback, "nimen");
//回調(diào)1 - 異步action執(zhí)行完才會執(zhí)行回調(diào) - action.BeginInvoke("cc", callback, "nimen")-2
action.BeginInvoke("cc", r =>
{
Console.WriteLine("11");
}, "nimen");
//回調(diào)2 -異步action執(zhí)行完才會執(zhí)行回調(diào)-(!asyncResult.IsCompleted)
while (!asyncResult.IsCompleted)
{
Console.WriteLine($"文件上傳99.9%..");
}
//回調(diào)3 -異步action執(zhí)行完才會執(zhí)行回調(diào)--信號量WaitOne()
asyncResult.AsyncWaitHandle.WaitOne();//等待異步任務完成后,才打印計算完成
asyncResult.AsyncWaitHandle.WaitOne(2000);//限時等待
// 回調(diào)4 - 異步action執(zhí)行完才會執(zhí)行回調(diào) - EndInvoke拿到委托函數(shù)的返回值
Func<int> func = () =>
{
return DateTime.Now.Day;
};
Console.WriteLine($"func.Invoke()={ func.Invoke()}");
IAsyncResult asyncResult1 = func.BeginInvoke(r =>
{
Console.WriteLine(r.AsyncState);
}, "nimen");
Console.WriteLine($"func.EndInvoke={ func.EndInvoke(asyncResult1)}");
//3.thread
//3.1.線程啟動 thread.Start();
ThreadStart threadStart = () => this.dosomething("cc");
Thread thread = new Thread(threadStart);
thread.Start();
//3.2.線等待程thread.Join();
thread.Join(500);//卡主線程
Console.WriteLine($"等待500ms");
thread.Join();
//3.3.thread.ThreadState /thread.IsBackfround
while (thread.ThreadState != ThreadState.Stopped)
{
Thread.Sleep(100);//cpu時間片交出去干其他的事,但是內(nèi)存還是占用
}
thread.IsBackground = true;//前臺線程,當軟件閃退時,會吐出日志
//4.threadPool
//4.1ThreadPool.GetMaxThreads
ThreadPool.QueueUserWorkItem(
t =>
{ this.dosomething("cc");
this.dosomething("dd");
});//接收一個沒有返回值的委托
ThreadPool.SetMaxThreads(16, 16);
ThreadPool.GetMaxThreads(out int Workerthreads, out int completionPortThreads);
Console.WriteLine($"Workerthreads:{Workerthreads}+completionPortThreads{completionPortThreads}");
//4.2.manualResetEvent
ManualResetEvent manualResetEvent = new ManualResetEvent(false);
ThreadPool.QueueUserWorkItem(t =>
{
this.dosomething("cc");
manualResetEvent.Set();
});//接收一個沒有返回值的委托
manualResetEvent.WaitOne();
Console.WriteLine($"等待ThreadPool.QueueUserWorkItem執(zhí)行完再執(zhí)行");
//5.task
Task.Run(() =>
{
this.dosomething("cc");
Console.WriteLine($"等待ThreadPool.QueueUserWorkItem執(zhí)行完再執(zhí)行");
});
new Task(() => this.dosomething("33")).Start();
TaskFactory taskFactory1 = Task.Factory;
taskFactory.StartNew(() => this.dosomething("44"));
//5.1 task.waitall、waitany .ContinueWith taskFactory.ContinueWhenAny
List<Task> tasklist1 = new List<Task>();
tasklist.Add(Task.Run(() => this.dosomething("33")));
tasklist.Add(Task.Run(() => this.dosomething("33")));
Task.WaitAny(tasklist.ToArray());
Task.WaitAll(tasklist.ToArray());
Task.WhenAll(tasklist.ToArray()).ContinueWith(t =>
{
Console.WriteLine($"等待ThreadPool.QueueUserWorkItem執(zhí)行完再執(zhí)行");
});
taskFactory.ContinueWhenAny(tasklist.ToArray(), t => { });
//5.2 task線程完成標識
Task task = new Task(t => { }, "CC");
Console.WriteLine(task.AsyncState);//會打印CC
//5.3thread.sleep()卡線程 task.delay()不卡線程
//5.4tasklist線程取消
CancellationTokenSource cts1 = new CancellationTokenSource();
tasklist.Add(taskFactory.StartNew(() => this.dosomething("44"), cts1.Token));
//6.parallel啟動多線程
Parallel.Invoke(
() => this.dosomething("11"),
() => this.dosomething("22"),
() => this.dosomething("33")
);
//6.1Parallel.For
Parallel.For(0, 5, i => this.dosomething(i));
Parallel.ForEach(new string[] { "0","1","2","3"},i=>this.dosomething("11"));
//6.2控制并發(fā)數(shù)量
ParallelOptions parallelOptions = new ParallelOptions();
parallelOptions.MaxDegreeOfParallelism = 3;
Parallel.For(0,40,parallelOptions,(i,state)=> {
if (i==2)
{
state.Break();
state.Stop();
}
});
//7.線程安全lock
//private static readonly object btn_click = new object();
int c = 0;
tasklist.Add(taskFactory.StartNew(() => {
int m = 3 + 2;
lock (btn_click)
{
c += 1;
}
}));
//8.await/asyncawait 后的代碼相當于回調(diào),只不過不是自己寫的,是編譯器狀態(tài)機自帶的。
//回調(diào)方法continuewith是子線程完成的,但await不僅僅是回調(diào)(可子線程可主線程,計算機分配),所以他們又有所不同
private static async void Async()
{
await Task.Run(() =>
{
Console.WriteLine($"等待ThreadPool.QueueUserWorkItem執(zhí)行完再執(zhí)行");
});
Console.WriteLine($"等待ThreadPool.QueueUserWorkItem執(zhí)行完再執(zhí)行");
}
}
}
}
到了這里,關(guān)于c#多線程—基礎概念到“雙色球”項目實現(xiàn)(附知識點目錄、代碼、視頻)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!