C#多线程基础
最近自己写了个小爬虫,里面用到了多线程技术,忽然发现对此技术竟然有些陌生了,于是乎开始疯狂的去问度娘,在此记录下来,以便自己和各位小伙伴们学习。
一、什么是线程
一个应用程序就相当于一个进程,进程拥有应用程序的所有资源进程包括线程,进程的资源被线程共享,但不拥有线程。我们可以打开电脑中的任务管理器,运行的.exe都是一个进程,里面的分支是线程。
二、多线程
多线程其实就是进程中一段并行运行的代码
1. 创建并启动线程
1 static void main() 2 { 3 //获取线程id 4 var threadid = thread.currentthread.managedthreadid; 5 var thread = new thread(test1); 6 thread.start(); 7 8 console.writeline(threadid + "_main()"); 9 console.read(); 10 } 11 12 /// <summary> 13 /// 测试方法 14 /// </summary> 15 private static void test1() 16 { 17 //获取线程id 18 var threadid = thread.currentthread.managedthreadid; 19 console.writeline(threadid + "_test()"); 20 for (int i = 0; i < 10; i++) 21 { 22 console.writeline(threadid + "_" + i); 23 } 24 }
结果:
2、暂定线程诺干时间
1 static void main() 2 { 3 //获取线程id 4 var threadid = thread.currentthread.managedthreadid; 5 var thread = new thread(test1); 6 thread.start(); 7 console.writeline($"主线程id{threadid}_main()"); 8 console.read(); 9 } 10 11 /// <summary> 12 /// 测试方法 13 /// </summary> 14 private static void test1() 15 { 16 //获取线程id 17 var threadid = thread.currentthread.managedthreadid; 18 console.writeline($"辅线程id{threadid}_test()"); 19 for (int i = 0; i < 10; i++) 20 { 21 thread.sleep(1000);//单位毫秒 22 console.writeline($"辅线程id{threadid}_{datetime.now}"); 23 } 24 }
结果:
3、线程合并
thread.join操作会阻塞当前线程,等待子线程完成后再进行运行。
1 static void main() 2 { 3 //获取线程id 4 var threadid = thread.currentthread.managedthreadid; 5 var thread = new thread(test1); 6 thread.start(); 7 console.writeline($"主线程id{threadid}_main()1"); 8 thread.join(); 9 console.writeline($"主线程id{threadid}_main()2"); 10 console.read(); 11 } 12 13 /// <summary> 14 /// 测试方法 15 /// </summary> 16 private static void test1() 17 { 18 //获取线程id 19 var threadid = thread.currentthread.managedthreadid; 20 console.writeline($"辅线程id{threadid}_test()"); 21 for (int i = 0; i < 10; i++) 22 { 23 thread.sleep(1000);//单位毫秒 24 console.writeline($"辅线程id{threadid}_{datetime.now}"); 25 } 26 }
结果:
4、线程终止
1 static void main() 2 { 3 //获取线程id 4 var threadid = thread.currentthread.managedthreadid; 5 var thread = new thread(test1); 6 thread.start(); 7 console.writeline($"主线程id{threadid}_main()1"); 8 thread.sleep(3000); 9 thread.abort(); 10 console.writeline($"主线程id{threadid}_main()2"); 11 console.read(); 12 } 13 14 /// <summary> 15 /// 测试方法 16 /// </summary> 17 private static void test1() 18 { 19 //获取线程id 20 var threadid = thread.currentthread.managedthreadid; 21 console.writeline($"辅线程id{threadid}_test()"); 22 for (int i = 0; i < 10; i++) 23 { 24 thread.sleep(1000);//单位毫秒 25 console.writeline($"辅线程id{threadid}_{datetime.now}"); 26 } 27 }
结果:
5、线程中的参数传递
1 static void main() 2 { 3 //获取线程id 4 var threadid = thread.currentthread.managedthreadid; 5 console.writeline($"主线程id{threadid}_main()"); 6 //第一种参数传递方式 7 var thread1 = new thread(() => test1("小魔王")); 8 thread1.start(); 9 10 //第二种参数传递方式(参数只能是一个,object类型) 11 var parameterizedthreadstart = new parameterizedthreadstart(test2); 12 var thread2 = new thread(parameterizedthreadstart); 13 thread2.start("大魔王"); 14 console.read(); 15 } 16 17 /// <summary> 18 /// 测试方法 19 /// </summary> 20 private static void test1(string name) 21 { 22 //获取线程id 23 var threadid = thread.currentthread.managedthreadid; 24 console.writeline($"辅线程id{threadid}_我的名字叫:{name}"); 25 } 26 27 /// <summary> 28 /// 测试方法 29 /// </summary> 30 private static void test2(object name) 31 { 32 //获取线程id 33 var threadid = thread.currentthread.managedthreadid; 34 console.writeline($"辅线程id{threadid}_我的名字叫:{name}"); 35 }
结果:
还有其他的传递方式,在此先不做说明了,这里只介绍thread提供的这么几种。
6、线程安全和线程锁lock
线程安全就是多线程访问时,采用了加锁机制,当一个线程访问该类的某个数据时,进行保护,其他线程不能进行访问直到该线程读取完,其他线程才可使用。线程安全情况下,不会出现数据不一致或者数据污染的问题。 线程不安全就是不提供数据访问保护,有可能出现多个线程先后更改数据造成所得到的数据是脏数据! 若每个线程中对全局变量、静态变量只有读操作,而无写操作,一般来说,这个全局变量是线程安全的;若有多个线程同时执行写操作,一般都需要考虑线程同步,否则的话就可能影响线程安全。
lock 关键字通过获取指定对象的互斥锁,将语句块标记为临界区,执行语句然后释放该锁。
lock 确保当一个线程位于代码的临界区时,另一个线程不进入临界区。如果其他线程试图进入锁定的代码,则它将一直等待(即被阻止),直到该对象被释放。使用lock,会导致整个应用程序串行化,降低程序的并发能力,影响性能。
到底什么场景下要使用lock保证线程安全:该串行就串行,该并行就并行。
加锁前:
1 public static int i = 1000000; 2 static void main() 3 { 4 //获取线程id 5 var threadid = thread.currentthread.managedthreadid; 6 for (int j = 0; j < 2; j++) 7 { 8 var thread = new thread(test1); 9 thread.start(); 10 } 11 console.read(); 12 } 13 14 /// <summary> 15 /// 测试方法 16 /// </summary> 17 private static void test1() 18 { 19 //获取线程id 20 var threadid = thread.currentthread.managedthreadid; 21 22 console.writeline($"辅线程id{threadid}_i初始值:{i}"); 23 int count = 0; 24 for (int j = 0; j < 1000000; j++) 25 { 26 i--; 27 count++; 28 } 29 console.writeline($"辅线程id{threadid}_运行次数:{count}"); 30 console.writeline($"辅线程id{threadid}_i结束值:{i}"); 31 }
结果:
加锁后:
1 public static int i = 1000000; 2 private readonly static object objlock = new object(); 3 static void main() 4 { 5 //获取线程id 6 var threadid = thread.currentthread.managedthreadid; 7 for (int j = 0; j < 2; j++) 8 { 9 var thread = new thread(test1); 10 thread.start(); 11 } 12 console.read(); 13 } 14 15 private static void test1() 16 { 17 //获取线程id 18 var threadid = thread.currentthread.managedthreadid; 19 20 int count = 0; 21 lock (objlock) 22 { 23 console.writeline($"辅线程id{threadid}_i初始值:{i}"); 24 for (int j = 0; j < 1000000; j++) 25 { 26 i--; 27 count++; 28 } 29 } 30 console.writeline($"辅线程id{threadid}_运行次数:{count}"); 31 console.writeline($"辅线程id{threadid}_i结束值:{i}"); 32 }
结果:
好啦,今天关于线程的知识就分箱到这里啦。