线程抢占执行怎么使10-20连续输出

图片说明
线程怎么使 10-20是连续输出的?
就是一旦th2开始执行了,先暂停th,等th2执行完再执行th

th.Start();
th.Join();
th2.Start();

中间加一行th.Join()即可,原理就是阻塞调用线程,直到其终止为止。

其实有一个锁的概念的在里面,这是最好也是最正确的解决方案,你可以在网上搜点关于这方面的资料了解一下。还有一些不正规的做法就是让其他的线程sleep几秒就好了啊。

这个是线程同步问题。.Net框架提供了很多方法实现,我就说说我比较熟悉的几种方法吧!

  1. 第一种方法如一楼所说。等待线程1执行完毕,然后再执行线程2

            th.Start();
            th.Join();
            th2.Start();

这种方法的优点是简单,缺点是不易扩展,若线程1与线程2都需要同时执行某段代码,或线程12的执行不希望影响主线程的执行。。。。。。
所以我们一定还有更好的方法实现这样的效果

  1. 第二中要讲的方法其实与第一种是一样的方法。不一样的地方是避免了主线程的阻塞, 代码如下:

 static void Main(string[] args)
        {

            Thread th = new Thread(() =>
                {
                    for (int i = 0; i < 10; i++) 
                    {
                        Console.WriteLine(i);
                        Thread.Sleep(100);
                    }
                });
            Thread th2 = new Thread(() =>
            {
                th.Join();
                for (int i = 10; i < 20; i++)
                {
                    Console.WriteLine(i);
                    Thread.Sleep(100);
                }
            });
            th.Start(); 
            th2.Start();
            Console.WriteLine("线程启动完毕!"); 

        }

此方法的优点正好避免了1的缺点,但它的缺点是我们必须知道线程1的实例。这在实际项目中有可能就很麻烦了,
如果有10个这样的线程需要进行同步执行。那10个线程都需要知道上一个线程的实例,并在自己的线程中等待。
这样写代码是难以读懂并维护的。就着代码简洁的原则,我们也需要考虑其它的实现放肆。

  1. 第三种方法我决定使用锁来实现。代码如下:
  static void Main(string[] args)
        {
            object ThreadLocker =new  object();
            Thread th = new Thread(() =>
                {
                    lock (ThreadLocker)
                    {
                        for (int i = 0; i < 10; i++)
                        {
                            Console.WriteLine(i);
                            Thread.Sleep(100);
                        }
                    }
                });
            Thread th2 = new Thread(() =>
            {
                lock (ThreadLocker)
                {
                    for (int i = 10; i < 20; i++)
                    {
                        Console.WriteLine(i);
                        Thread.Sleep(100);
                    }
                }
            });

            Thread th3 = new Thread(() =>
            {
                lock (ThreadLocker)
                {
                    for (int i = 20; i < 30; i++)
                    {
                        Console.WriteLine(i);
                        Thread.Sleep(100);
                    }
                }
            });
            th.Start();
            while (th.ThreadState != ThreadState.Running)
            {
                //Console.WriteLine("等待线程1执行"); 
            }
            th2.Start();
            while (th2.ThreadState != ThreadState.Running)
            {
                //Console.WriteLine("等待线程2执行");
            }
            th3.Start();
            while (th3.ThreadState != ThreadState.Running)
            {
                //Console.WriteLine("等待线程3执行");
            }
            Console.WriteLine("线程启动完毕!"); 

        }

线程锁来决定对资源的互斥,注意代码中在主线程中用while判断线程的状态是为了达到线程顺序启动的目的(因为在多核的情况下,线程的执行顺序是不确定的)。
注意这里开了三个线程,在while等待的时候我起初准备使用Console.WriteLine来打印确定时序,实际发现这样并不能精准反映时序。因为这里涉及到Console.WriteLine的线程安全问题,
此问题不在本题讨论范围内,可以考虑使用System.Diagnostics.Debug.WriteLine在调试状态下查看输出窗口。
还有个要注意的是: 主线程的执行还是会阻塞!虽然只有很少的时间,若主线程少量阻塞不影响程序的功能,那这种方法是可行的,但若对要求较高,那我们还得考虑其它方法。

  1. 第四种方法,使用信号量。

        static void Main(string[] args)
        {
            int iThreadNum = 3;
            AutoResetEvent[] evts = new AutoResetEvent[iThreadNum];
            for (int i = 0; i < iThreadNum; i++)
            {
                evts[i] = new AutoResetEvent(false);
            } 
            Thread th = new Thread(() =>
             {  
                 for (int i = 0; i < 10; i++)
                 {
                     Console.WriteLine(i);
                     Thread.Sleep(100);
                 }
                 evts[0].Set();
             });
            Thread th2 = new Thread(() =>
            { 
                evts[0].WaitOne();  
                for (int i = 10; i < 20; i++)
                {
                    Console.WriteLine(i);
                    Thread.Sleep(100);
                }
                evts[1].Set();
            });

            Thread th3 = new Thread(() =>
            {
                evts[1].WaitOne(); 
                for (int i = 20; i < 30; i++)
                {
                    Console.WriteLine(i);
                    Thread.Sleep(100);
                } 
            });
            th3.Start();
            th2.Start();
            th.Start();
            Console.WriteLine("线程启动完毕!"); 

        }

使用信号量其实与第二种方法有些类似,不过这种方式更加灵活,不用等到线程结束。

好了,我要说的就这么多了,对以上几种方法用到的类有何疑问,可以查看msdn文档

ps:本文中的代码只看懂测试,实际这样写代码我是会很生气的!
最后建议下题主:下次问问题能够附上代码,答题的人一定会喜欢直接copy代码写测试的。