• 39.多线程


    为什么要用多线程

    • 让计算机"同时"做多件事情,节约时间。
    • 多线程可以让一个程序“同时”处理多个事情。
    • 后台运行程序,提高程序的运行效率,也不会使主界面出现无响应的情况。
    • 获得当前线程和当前进程

    如何实现多线程?

    • 编写产生线程所要执行的方法
    • 引用System.Threading命名空间
    • 实例化Thread类,并传入一个指向线程所要运行方法的委托。(这时候这个线程已经产生,但是还没有运行)
    • 调用Thread实例的Start方法,标记该线程可以被CPU执行了,但具体执行时间由CPU决定。

    前台线程和后台线程

    前台线程

    只有所有的前台线程都关闭才能完成程序关闭。主线程也是前台线程

    后台线程

    只要所有的前台线程结束,后台线程自动结束。

    实现

    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 WindowsFormsApp8 {
        public partial class Form1 : Form {
            public Form1() {
                InitializeComponent();
            }
    
            private void button1_Click(object sender, EventArgs e) {
                //创建一个线程去执行这个方法,默认情况下新创建的线程都是前台线程
                Thread th = new Thread(Test);
                //标记这个线程准备就绪了,可以随时被执行。具体什么时候执行这个线程,
                //由cpu决定
                //将线程设置为后台线程
                th.IsBackground = true;
                th.Start();
            }
    
            private void Test() {
                for (int i = 0; i < 500000; i++) {
                    Console.WriteLine(i);
                }
            }
    
    
        }
    }
    
    

    当创建的线程为前台线程时,会出现如下图所示现象,当关闭窗体时,创建的那个线程依旧在执行。而当将此线程设为后台线程后,就不会出现这种现象了。

    在.Net下,是不允许跨线程的访问。

    例如:

    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 WindowsFormsApp8 {
        public partial class Form1 : Form {
            public Form1() {
                InitializeComponent();
            }
    
            private void button1_Click(object sender, EventArgs e) {
                //创建一个线程去执行这个方法,默认情况下新创建的线程都是前台线程
                Thread th = new Thread(Test);
                //标记这个线程准备就绪了,可以随时被执行。具体什么时候执行这个线程,
                //由cpu决定
                //将线程设置为后台线程
                //th.IsBackground = true;
                th.Start();
            }
    
            private void Test() {
                for (int i = 0; i < 10000; i++) {
                    //Console.WriteLine(i);
                    textBox1.Text = i.ToString();
                }
            }
    
    
        }
    }
    
    

    运行:

    textbox1控件是由主线程创建的,它所在的Test()方法被新线程执行了,当创建的新线程想要访问另一个线程(主线程)中的资源时,应用程序并不允许这样做。在.Net下,是不允许跨线程的访问。

    可以这样进行修改

    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 WindowsFormsApp8 {
        public partial class Form1 : Form {
            public Form1() {
                InitializeComponent();
            }
    
            private void button1_Click(object sender, EventArgs e) {
                //创建一个线程去执行这个方法,默认情况下新创建的线程都是前台线程
                Thread th = new Thread(Test);
                //标记这个线程准备就绪了,可以随时被执行。具体什么时候执行这个线程,
                //由cpu决定
                //将线程设置为后台线程
                //th.IsBackground = true;
                th.Start();
            }
    
            private void Test() {
                for (int i = 0; i < 10000; i++) {
                    //Console.WriteLine(i);
                    textBox1.Text = i.ToString();
                }
            }
    
            private void Form1_Load(object sender, EventArgs e) {
                //取消跨线程的访问的限制
                //Control是winform中控件的基类
                //CheckForIllegalCrossThreadCalls:指示是否捕获对错误线程的调用
                Control.CheckForIllegalCrossThreadCalls = false;
            }
        }
    }
    
    

    但是当关闭程序时,有时也会出现问题如下图。

    出现这种问题的原因是:虽然关闭了程序,但由于种种原因,新线程并没有马上关闭,也就意味着新线程还会访问textbox1,但是主线程一关,资源将被释放掉,textbox1也就不存在了,新线程就访问不到textbox1了。
    所以可以在关闭程序时判断下这个新线程是否为null,如果这个新线程th为null,那么就是主线程结束了,这个新线程也结束了。如果不为null,那么意味着主线程虽然关了,但由于某些原因,新线程并没有马上关闭,这时我们可以手动的进行关闭。

    解决:

    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 WindowsFormsApp8 {
        public partial class Form1 : Form {
            public Form1() {
                InitializeComponent();
            }
            Thread th;
            private void button1_Click(object sender, EventArgs e) {
                //创建一个线程去执行这个方法,默认情况下新创建的线程都是前台线程
                 th = new Thread(Test);
                //标记这个线程准备就绪了,可以随时被执行。具体什么时候执行这个线程,
                //由cpu决定
                //将线程设置为后台线程
                //th.IsBackground = true;
                th.Start();
            }
    
            private void Test() {
                for (int i = 0; i < 10000; i++) {
                    //Console.WriteLine(i);
                    textBox1.Text = i.ToString();
                }
            }
    
            private void Form1_Load(object sender, EventArgs e) {
                //取消跨线程的访问
                //Control是winform中控件的基类
                //CheckForIllegalCrossThreadCalls:指示是否捕获对错误线程的调用
                Control.CheckForIllegalCrossThreadCalls = false;
            }
    
            private void Form1_FormClosing(object sender, FormClosingEventArgs e) {
                //当你点击关闭窗体的时候,判断新线程是否为null
                if (th != null) {
                    //结束这个线程,线程被Abort后就不能再重新Start了
                    th.Abort();
                }
            }
        }
    }
    
    

    注意 如果线程执行的方法需要参数,那么要求这个参数必须是object类型.

     private void button1_Click(object sender, EventArgs e)
            {
                Thread th = new Thread(Test);
                th.IsBackground = true;
                th.Start("123");
                //Test();
            }
    
    
    private void Test(object s){
               string ss = (string)s;
               for (int i = 0; i < 10000; i++){
                    Console.WriteLine(i);
               }
    }
    

    方法

    Start():启动线程(告诉CPU 我可以被执行了,具体什么时候执行,由CPU决定)
    Abort():终止线程 终止完成之后不能再Start()
    Thread.Sleep() 静态方法,可以使当前线程停止一段时间运行
    Thread.CurrentThread:获得当前的线程引用

  • 相关阅读:
    Java static 静态代码块、代码块
    blog
    Java 类之间的关系
    vscode Cannot edit in read-only editor.
    以KNN为例用sklearn进行数据分析和预测
    Python 时间处理
    Python map filter reduce enumerate zip 的用法
    Python列出文件夹中的文件
    Java类只加载一次的情况
    Powershell 中的管道
  • 原文地址:https://www.cnblogs.com/lz32158/p/12977574.html
Copyright © 2020-2023  润新知