线程Thread基础学习(2)

继上一篇文章之后,再来讨论lock与join 使用和区别:

接下来先看join使用方法一,首先定义线程测试类TestThread,代码如下:

 1     public class TestThread
 2     {
 3         public static void Test1()
 4         {
 5                 for (int i = 0; i < 10; i++)
 6                 {
 7                     Console.WriteLine("Test1");
 8                 }
 9         }
10         public static void Test2(object s)
11         {
12                 for (int i = 0; i < 10; i++)
13                 {
14                     Console.WriteLine(s);
15                 }
16         }
17     }

测试代码:

1  static void Main(string[] args)
2         {
3             //继博文"线程Thread基础学习(1) "之后,继续讨论并发信息的同步方法
4             Thread thread1 = new Thread(TestThread.Test1);
5             Thread thread2 = new Thread(TestThread.Test2);
6             thread1.Start();
7             thread2.Start("Test2");
8         }

执行结果如下:输出没有规律,无章可循
Test1
Test1
Test1
Test1
Test1
Test1
Test1
Test2
Test2
Test2
Test2
Test2
Test2
Test2
Test2
Test2
Test2
Test1
Test1
Test1
请按任意键继续. . .

接下来join登场,改造main代码如下:

1   static void Main(string[] args)
2         {
3             //继博文"线程Thread基础学习(1) "之后,继续讨论并发信息的同步方法
4             Thread thread1 = new Thread(TestThread.Test1);
5             Thread thread2 = new Thread(TestThread.Test2);
6             thread1.Start();
7             thread1.Join();
8             thread2.Start("Test2"); 
9         }

执行结果只有一种,如下:

Test1
Test1
Test1
Test1
Test1
Test1
Test1
Test1
Test1
Test1
Test2
Test2
Test2
Test2
Test2
Test2
Test2
Test2
Test2
Test2
请按任意键继续. . .

到这是否会想到join和lock的作用相似?从这点看,是很相似,但join可比lock坚强的,看看join官方说明:

      使用此方法确保线程已终止。 如果线程不终止,则调用方将无限期阻塞 如果调用 Join 时该线程已终止,此方法将立即返回。 此方法更改调用线程的状态以包括 ThreadState.WaitSleepJoin 对处于 ThreadState.Unstarted 状态的线程不能调用 Join

接下来来验证无限期阻塞特点,改造TestThread的Test1和Test2方法,代码如下:

 1         static object obj = new object();
 2         public static void Test1()
 3         {
 4             lock (obj)
 5             {
 6                 for (int i = 0; i < 10; i++)
 7                 {
 8                     Console.WriteLine("Test1");
 9                 }
10                 Thread thread = new Thread(new ParameterizedThreadStart(Test2));
11                 thread.Start("Test1.Test2");
12                 for (int i = 0; i < 10; i++)
13                 {
14                     Console.WriteLine("Test1");
15                 }
16             }
17         }
18         public static void Test2(object s)
19         {
20             lock (obj)
21             {
22                 for (int i = 0; i < 10; i++)
23                 {
24                     Console.WriteLine(s);
25                 }
26             }
27         }

测试代码:

1   static void Main(string[] args)
2         {
3             //继博文"线程Thread基础学习(1) "之后,继续讨论并发信息的同步方法
4             Thread thread1 = new Thread(TestThread.Test1);
5             thread1.Start();
6         }

测试结果只有一种:那就是20个Test1永远在前面并且连续,不会被Test2隔开,因为test2中lock操作无阻塞thead2执行,直到父进程Thraed1释放lock的obj对象才会执行。这点没有异议,和第一篇讲解的lock使用没有冲突。

Test1
Test1
Test1
Test1
Test1
Test1
Test1
Test1
Test1
Test1
Test1
Test1
Test1
Test1
Test1
Test1
Test1
Test1
Test1
Test1
Test1.Test2
Test1.Test2
Test1.Test2
Test1.Test2
Test1.Test2
Test1.Test2
Test1.Test2
Test1.Test2
Test1.Test2
Test1.Test2
请按任意键继续. . .

接下来再来看看join的功能,改造Test1和Test2方法,代码如下:

 1     public class TestThread
 2     {
 3         static object obj = new object();
 4         public static void Test1()
 5         {
 6             lock (obj)
 7             {
 8                 for (int i = 0; i < 10; i++)
 9                 {
10                     Console.WriteLine("Test1");
11                 }
12                 Thread thread = new Thread(new ParameterizedThreadStart(Test2));
13                 thread.Start("Test1.Test2");
14                 thread.Join();
15                 for (int i = 0; i < 10; i++)
16                 {
17                     Console.WriteLine("Test1");
18                 }
19             }
20         }
21         public static void Test2(object s)
22         {
23             lock (obj)
24             {
25                 for (int i = 0; i < 10; i++)
26                 {
27                     Console.WriteLine(s);
28                 }
29             }
30         }
31     }

测试代码:

1 static void Main(string[] args)
2         {
3             //继博文"线程Thread基础学习(1) "之后,继续讨论并发信息的同步方法
4             Thread thread1 = new Thread(TestThread.Test1);
5             thread1.Start();
6         }

看执行结果发生了什么?

Test1
Test1
Test1
Test1
Test1
Test1
Test1
Test1
Test1
Test1

        没有了“请按键继续...”的说明,说明Main没有结束,线程发生了阻塞,并在等待,我们在看看Test2中的代码,有lock,并且锁定的对象和Test1中是同一个对象,再想想join的官方说明,判断此时的情况就是发生了死锁,两个线程在等待对方释放obj资源。显然遮掩的逻辑不正确,接下来继续修改Test2方法,代码如下:

1         public static void Test2(object s)
2         {
3             for (int i = 0; i < 10; i++)
4             {
5                 Console.WriteLine(s);
6             }
7         }

去掉lock语句,在此执行结果如下:
Test1
Test1
Test1
Test1
Test1
Test1
Test1
Test1
Test1
Test1
Test1.Test2
Test1.Test2
Test1.Test2
Test1.Test2
Test1.Test2
Test1.Test2
Test1.Test2
Test1.Test2
Test1.Test2
Test1.Test2
Test1
Test1
Test1
Test1
Test1
Test1
Test1
Test1
Test1
Test1
请按任意键继续. . .

            由运行结果可以看出,当线程1执行到语句“Thread2.Join()”时,线程2被插入到线程1之前,两个线程合并到一起,变为顺序执行,直到执行完线程2中的所有语句,才去执行线程1中剩余的语句。

  换句话说,当我们在线程1中调用Thread2.Join()时,该方法只有在线程Thread2执行完毕之后才会返回。Join()函数还可以接受一个表示毫秒数的参数,当达到指定时间后,如果线程2还没运行完毕,那么Join函数将返回,这时线程1和线程2会处于互不干扰的两个线程,执行结果也不尽相同。

代码改造如下:

 1  public class TestThread
 2     {
 3         static object obj = new object();
 4         public static void Test1()
 5         {
 6             lock (obj)
 7             {
 8                 for (int i = 0; i < 10; i++)
 9                 {
10                     Console.WriteLine("Test1");
11                 }
12                 Thread thread = new Thread(new ParameterizedThreadStart(Test2));
13                 thread.Start("Test1.Test2");
14                 thread.Join(10);
15                 for (int i = 0; i < 10; i++)
16                 {
17                     Console.WriteLine("Test1");
18                 }
19             }
20         }
21         public static void Test2(object s)
22         {
23             for (int i = 0; i < 50; i++)
24             {
25                 Console.WriteLine(s);
26             }
27         }
28     }

测试代码:

1  static void Main(string[] args)
2         {
3             //继博文"线程Thread基础学习(1) "之后,继续讨论并发信息的同步方法
4             Thread thread1 = new Thread(TestThread.Test1);
5             thread1.Start();
6         }

执行结果:

Test1
Test1
Test1
Test1
Test1
Test1
Test1
Test1
Test1
Test1
Test1.Test2
Test1.Test2
Test1.Test2
Test1.Test2
Test1.Test2
Test1.Test2
Test1.Test2
Test1.Test2
Test1.Test2
Test1.Test2
Test1.Test2
Test1.Test2
Test1.Test2
Test1.Test2
Test1.Test2
Test1.Test2
Test1.Test2
Test1.Test2
Test1.Test2
Test1.Test2
Test1.Test2
Test1.Test2
Test1.Test2
Test1.Test2
Test1.Test2
Test1.Test2
Test1.Test2
Test1.Test2
Test1.Test2
Test1.Test2
Test1.Test2
Test1.Test2
Test1.Test2
Test1.Test2
Test1.Test2
Test1.Test2
Test1.Test2
Test1.Test2
Test1.Test2
Test1.Test2
Test1
Test1
Test1
Test1
Test1
Test1
Test1
Test1
Test1.Test2
Test1.Test2
Test1.Test2
Test1.Test2
Test1.Test2
Test1.Test2
Test1.Test2
Test1.Test2
Test1
Test1
Test1.Test2
Test1.Test2
请按任意键继续. . .

验证完毕!!

结论:

        使用Join方法确保线程已终止。 如果线程不终止,则调用方将无限期阻塞。 如果调用 Join 时该线程已终止,此方法将立即返回。此方法更改调用线程的状态以包括 ThreadState.WaitSleepJoin 对处于 ThreadState.Unstarted 状态的线程不能调用 Join

那些曾以为念念不忘的事情就在我们念念不忘的过程中,被我们遗忘了。
原文地址:https://www.cnblogs.com/niuww/p/3028434.html