1. 程式人生 > >【.NET執行緒--進階(一)】--執行緒方法詳解

【.NET執行緒--進階(一)】--執行緒方法詳解



       上篇部落格從執行緒的基本概況開始著重討論了執行緒,程序,程式之間的區別,然後討論了執行緒操作的幾個類,並通過例項來說明了執行緒的建立方法。本篇部落格將會帶大家更深入的瞭解執行緒,介紹執行緒的基本方法,並通過一個Demo使用委託來呼叫執行緒之外的物件。

執行緒

   多執行緒優缺點

         多執行緒的使用會幫助程式提高響應速度,因為可以同時執行多個任務這樣對比一個個的來完成任務來說提高了響應的速度,較之新增多CPU來說多執行緒提高了強大的技術來執行多個任務。雖然多執行緒提高了響應速度,但同時犧牲了資源,由於多執行緒的執行它會佔用多個資源,為了避免資源訪問的衝突,往往會在每個執行緒中都會建立自己的資源,這樣導致了資源的浪費。另外如果執行緒過多,則其中大多數執行緒都不會產生明顯的進度,

如果大多數當前執行緒處於一個程序中,則其他程序中的執行緒的排程頻率就會很低。

  執行緒基本方法

         下表包括了線上程程式設計過程中常用的基本方法。

可用於控制單個執行緒的方法

方法 操作
Start  使執行緒開始執行。
Sleep 使執行緒暫停指定的一段時間。
Suspend 線上程到達安全點時,使其暫停。
Abort  線上程到達安全點時,使其停止。
Resume 重新啟動掛起的執行緒
Join 使當前執行緒一直等到另一執行緒完成。 在與超時值一起使用時,如果該執行緒在分配的時間內完成,此方法將返回 True。

       Note: 安全點是指程式碼中公共語言執行時可以安全地執行自動“垃圾回收”的位置。垃圾回收是指釋放不再使用的變數並回收記憶體的過程。 呼叫執行緒的 Abort 或 Suspend 方法時,公共語言執行時將對程式碼進行分析,確定讓執行緒停止執行的適當位置。

  Demo1:執行緒,方法--委託

       自己做的一個小Demo來實現多執行緒,當點選開始按鈕後會在文字框中填寫數字,與此同時載入進度條,讀取進度,點選暫停後執行緒會停止。另外可以在文字框中輸入暫停時間來指定執行緒暫停時間,在暫停後繼續執行。

       在點選開始按鈕後會同時建立兩個執行緒,分別為showNumThread和pBarThread,用來向文字框中寫入數字和載入進度條。這裡需要說明的是,一般情況下執行緒內部是不允許呼叫執行緒外建立的物件的,建立的兩個執行緒都呼叫了執行緒外部的物件,是怎麼實現的呢?使用的是委託來非同步執行程式來實現了呼叫執行緒外部的方法。

/// <summary>
/// 開始按鈕事件,建立執行緒併為執行緒指定方法
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnStart_Click(object sender, EventArgs e)
{
    pBarThread = new Thread(new ThreadStart(this.ExepBarShow)); //建立進度條執行緒
    showNumThread = new Thread(new ThreadStart(this.ExeShowNum));   //建立顯示文字框中的文字執行緒
    //開始兩個已建立的執行緒
    this.StartThread(showNumThread);    
    this.StartThread(pBarThread);
}

/// <summary>
/// 使用委託執行ShowNumToText方法
/// </summary>
private void ExeShowNum()
{
    try
    {
        MethodInvoker mInvoker = new MethodInvoker(this.ShowNumToText); //宣告託管委託,併為委託執行執行的方法

        //執行委託方法,向Text中寫入文字
        while (true)
        {
            this.BeginInvoke((Delegate)mInvoker);   //非同步執行執行的委託
            Thread.Sleep(1000);     //執行緒停頓1秒後繼續執行 
        }
    }
    catch { }
}

/// <summary>
/// 先文字框txtNum中寫入文字
/// </summary>
private void ShowNumToText()
{
    i = i + 1;  //i累加
    txtNum.Text = txtNum.Text + " " + (i + 1).ToString();   //向txtNum中寫入文字
}

/// <summary>
/// 執行pBarShow方法,載入進度條,讓進度條讀取進度
/// </summary>
private void ExepBarShow()
{
    try
    {
        MethodInvoker mInvoker = new MethodInvoker(this.pBarShow);  //宣告並建立委託,為委託執行進度

        //非同步執行委託
        while (true)
        {
            this.BeginInvoke((Delegate)mInvoker);
            Thread.Sleep(10);
        }
    }
    catch { }
}

/// <summary>
/// 執行進度條讀取進度
/// </summary>
private void pBarShow()
{
    this.pgBar.PerformStep();
}

/// <summary>
/// 執行緒開始方法
/// </summary>
/// <param name="th">Thread物件,需要開始的執行緒</param>
private void StartThread(Thread th) {
    th.Start();
}

/// <summary>
/// 執行緒結束方法
/// </summary>
/// <param name="th">Thread物件,需要結束的執行緒</param>
private void EndThread(Thread th) {
    th.Interrupt(); //中斷執行緒
    th.Abort(); //終止執行緒
    th = null;
}

/// <summary>
/// 停止執行緒事件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnStop_Click(object sender, EventArgs e)
{
    try
    {
        this.TestThead();   //驗證執行緒是否存在,如果沒有存在將會拋錯
        this.EndThread(this.pBarThread);    //結束執行緒
        this.EndThread(this.showNumThread); //結束執行緒
    }
    catch (Exception ex)
    {
        //提示錯誤資訊
        MessageBox.Show(ex.Message , "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
    }
            
}

/// <summary>
/// 終止執行緒事件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnEnd_Click(object sender, EventArgs e)
{
    try
    {
        this.TestThead();   //驗證執行緒是否建立
        this.EndThread(this.pBarThread);//結束執行緒
        this.EndThread(this.showNumThread); //結束執行緒
        txtNum.Text = "";   //清空文字框內容
        i = 0;  //數字充值
        this.pgBar.Value = 0;//進度條重置
    }
    catch (Exception ex)
    {
        //顯示錯誤資訊
        MessageBox.Show(ex.Message, "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
    }     
}

/// <summary>
/// 執行指定執行緒停頓時間
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnStopMinute_Click(object sender, EventArgs e)
{
    try
    {
        int j = int.Parse(textBox1.Text);   //獲取終止的時間
        Thread.Sleep(j);    //將執行緒暫停指定的時間
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message, "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
    }        
}

/// <summary>
/// 驗證執行緒是否存在方法
/// </summary>
private void TestThead() {
    if (pBarThread ==null)
    {
        throw new Exception ("未建立執行緒,請建立執行緒後操作!");
    }

    if (showNumThread  == null)
    {
        throw new Exception ("未建立執行緒,請建立執行緒後操作!");
    }
}

  Demo2:Join方法使用例項

       Join方法能在指定的執行緒中插入一個執行緒,當插入的執行緒執行完成後才會繼續執行被插入的執行緒。.NET為我們過載了此方法,能夠為方法傳遞引數來指定經過的時間,此時該方法的作用與Sleep相類似,執行經過多長時間後來執行被插入的執行緒。Join方法的靈活執行能夠實現執行緒之間的執行順序。

using System;
using System.Threading;

namespace TestJoin
{
    /// <summary>
    /// Join方法驗證例項,執行緒t1使用了join方法,執行緒t2沒有使用join方法
    /// </summary>
    class Program
    {
        static void Main(string[] args)
        {
            //建立新執行緒,為執行緒執行行為
            Thread t1 = new Thread(() =>
            {
                Thread.Sleep(1000);
                Console.WriteLine("t1 is ending.");
            });
            t1.Start(); //開始執行緒

            t1.Join();  //在主執行緒中插入t1執行緒,先執行t1,執行緒後執行主執行緒
            Console.WriteLine("t1.Join() returned.");   //執行主執行緒,提示t1已經完成


            //建立新執行緒,為執行緒執行行為
            Thread t2 = new Thread(() =>
            {
                Thread.Sleep(1000);
                Console.WriteLine("t2 is ending.");
            });
            t2.Start(); //開始執行緒

            Console.WriteLine("t2.Join() returned.");   //執行主執行緒,提示t1已經完成
            Console.ReadLine();
        }
    }
}
/*輸出結果:
 *t1 is ending.
 *t1.Join() returned.
 *
 *t2.Join() returned.
 *t2 is ending.
 */
     輸出結果:
              

         從輸出結果上分析可以得出,Join方法將建立的執行緒插入到了主執行緒中當執行完後再繼續執行主執行緒,對應到Demo2中是執行緒t1插入到了主執行緒中,這樣會首先執行t1執行緒在控制檯上列印“t1 is ending”列印完成後t1執行緒結束,然後繼續執行主執行緒來列印其它的文字。所以我們完全可以說Join方法是將一個執行緒插入到主執行緒中,當執行完插入的執行緒後再繼續執行被插入的執行緒。

結語

      執行緒的優缺點決定了在開發過程中是否使用多執行緒,另外靈活執行單執行緒的方法來實現靈活的控制執行緒,兩個Demo使用了執行緒的基本方法,能夠更加深刻的瞭解它們的使用。下篇部落格將會更加深入的討論執行緒和執行緒之間的呼叫關係,以及如何實現執行緒間的資料傳遞及檢索。

相關推薦

.NET執行----執行方法

        上篇部落格從執行緒的基本概況開始著重討論了執行緒,程序,程式之間的區別,然後討論了執行緒操作的幾個類,並通過例項來說明了執行緒的建立方法。本篇部落格將會帶大家更深入的瞭解執行緒,介紹執行緒的基本方法,並通過一個Demo使用委託來呼叫執行緒之外的物件。

前端基礎12:深入核心,事件迴圈機制

Event Loop JavaScript的學習零散而龐雜,因此很多時候我們學到了一些東西,但是卻沒辦法感受到自己的進步,甚至過了不久,就把學到的東西給忘了。為了解決自己的這個困擾,在學習的過程中,我一直試圖在尋找一條核心的線索,只要我根據這條線索,我就能夠一點一點的進步。 前端基礎進階正是圍繞這條線索

執行與高併發程式設計

前言: 使用多執行緒的目的: 充分利用CPU資源,提高程式執行速度 使用多執行緒面臨的挑戰: 上下文切換、死鎖、計算機軟硬體資源的限制等問題 結論: 不是一味地開啟執行緒就能夠讓程式最大限度地併發執行,以及提升執行速度,想利用多執行緒提升程式執行速度需要結合實際

C語言實現串列埠通訊知識點整理執行、開啟串列埠、設定波特率、設定校驗位、互斥鎖等實現基本的通訊

  部分程式碼借鑑地址:https://blog.csdn.net/wangqingchuan92/article/details/73497354/ 謝謝! 1.建立執行緒線上程內進行串列埠之間的收發 void CREAT_pthread(void) { pthr

JAVA06執行

一、三個概念 1、程式 程式(Program)是一個靜態的概念,一般對應於作業系統中的一個可執行檔案 2、程序 (1)執行中的程式叫做程序(Process),是一個動態的概念 (2)特點: 程序是程式的一次動態執行過程, 佔用特定的地址空間 每個程序由3

Java多執行三七—— J.U.C之collections框架:LinkedBlockingDeque

一、LinkedBlockingDeque簡介 LinkedBlockingDeque和ConcurrentLinkedDeque類似,都是一種雙端佇列的結構,只不過LinkedBlockingDeque同時也是一種阻塞佇列,它是在JDK1.5時隨著J.U.C包引

Java多執行三八—— J.U.C之collections框架:LinkedTransferQueue

一、LinkedTransferQueue簡介 LinkedTransferQueue是在JDK1.7時,J.U.C包新增的一種比較特殊的阻塞佇列,它除了具備阻塞佇列的常用功能外,還有一個比較特殊的transfer方法。 我們知道,在普通阻塞佇列中,當佇列為空時,

PyQt5——多執行:QTimer

應用程式開發中多執行緒的必要性: 一般情況下,應用程式都是單執行緒執行的,但是對GUI程式來說,單執行緒有時候滿足不了要求,但是對於一些特殊情況:比如一個耗時較長的操作,執行過程會有卡頓讓使用者以為程式出錯而把程式關閉或是系統本身認為程式執行出錯而自動關閉程式。這個時候就

PyQt5——多執行:QThread & 事件處理

接上篇… 2. QThread 要使用QThread開始一個執行緒,可以建立它的一個子類,然後覆蓋其QThread.run()函式 class Thread(QThread): def __init__(self): super().__init__()

PyQt5——多執行:QThread & 事件處理

接上篇… 2. QThread 要使用QThread開始一個執行緒,可以建立它的一個子類,然後覆蓋其QThread.run()函式 class Thread(QThread): def __init__(self): su

python9執行

# 什麼是執行緒? 執行緒也叫`輕量級程序`,是作業系統能夠進行`運算排程`的`最小`單位,它被包涵在程序之中,是程序中的實際運作單位。執行緒自己不擁有`系統資源`,只擁有一點兒在執行中必不可少的資源,但它可與同屬一個程序的其他執行緒共享程序所擁有的全部資源。一個執行緒可以建立和撤銷另一個執行緒,同一個程序中

mysql mysql備份

mysql備份的目的: 實現災難恢復:誤操作、硬件故障、軟件故障、自然災害、黑客攻擊 註意的要點: 1、能夠容忍丟失多少數據 2、恢復數據所用的時間 3、備份需要的時間 4、是否對業務有影響 5、備份時服務器負載 備份類型 完全備份:備份整個

函數

並行 自己的 習題 文件 false 聲明 方式 關鍵字 true 1.命名空間 本質:存放名字與值的綁定關系 命名空間的分類:(1)全局命名空間(變量)->位於函數體外 (2)局部命名空間(變量)->

Redis高級

具體類 tro 類型 長度 刪除過期數據 專用 影響 生活 設置時間 一、redis中的事務 在關系型數據庫中事務是必不可少的一個核心功能,生活中也是處處可見,比如我們去銀行轉賬,首先需要將A賬戶的錢劃走,然後存到B賬戶上,這兩個步驟必須在同一事務中,要麽都執行,要麽都不執

SQL ServerT-SQL查詢和編程的背景

.com src 編程 server 分享 bubuko 進階 分享圖片 img SQL Server進階(一)T-SQL查詢和編程的背景

Redis高階

一、redis中的事務 在關係型資料庫中事務是必不可少的一個核心功能,生活中也是處處可見,比如我們去銀行轉賬,首先需要將A賬戶的錢划走,然後存到B賬戶上,這兩個步驟必須在同一事務中,要麼都執行,要麼都不執行,不然錢憑空消失了,換了誰也無法接受。 同樣,redis中也為我們提供了事務,原理是:先把一組同一事

SpringCloud從入門到——懂生活就懂微服務

避免 發現 官方文檔 隨著 並發 規範 只需要 組合 組件 內容   本文通過生活中的實際場景解釋單體應用和微服務應用的關系,以及SpringCloud中各組件的功能和含義。 適合人群   Java開發人員 說明   轉載請說明出處:SpringCloud從入門到進階(一)

Servlet第一個JSP頁面

前言       本章講解JSP的相關知識之JSP初步 方法 1.概念 在以前我們寫網頁的時候,都是用html進行書寫,這種網頁是靜態的,無法和伺服器進行一個互動,那麼怎麼辦呢?JSP技術應運而生,我們在web開發之中,Java和Jsp可以形成完美的

JavaScriptJS事件機制

前言       做了這麼久的鋪墊,終於迎來了新的篇章,該章介紹JS中的事件機制 方法 1.概念 我們知道,JS是參與網頁互動的一門指令碼語言,之前所說的都是JS的基本概念,那麼怎麼來進行互動呢!那就需要JS的事件機制來進行控制了,如按鈕的點選事件觸

Android: Launcher啟動過程

1.前言 最近一直在看 《Android進階解密》 的一本書,這本書編寫邏輯、流程都非常好,而且很容易看懂,非常推薦大家去看看(沒有收廣告費,單純覺得作者寫的很好)。 今天就將 Launcher 系統啟動過程 總結一下(基於Android 8.0 系統)。 文章