线程没有睡觉

时间:2015-02-22 14:30:43

标签: java multithreading

我是使用Threads的新手,我只是做了一个小程序来了解它是如何工作的。作为一个例子,做了一个素数练习,程序运行得很完美,但我发现如果我不使用sleep(),每次按下运行时数字的顺序都会改变(不改变代码) 。那么为什么会这样呢?

    class Prime extends ThreadDemo implements Runnable 
    {
    public void run()
    {
        for(int i=2;i<=20;i++)
        {
            if(prime(i))
            {
                System.out.printf ("Prime No.= %d \n",i);
            }
        }
    }
    }

    class notPrime extends ThreadDemo implements Runnable
    {
       int number= 0;
       public void run()
       {
           prime(number);
       }
    }

class ThreadDemo
{
    public boolean prime(int start_value)
    {
        for(int i=2; i<start_value; i++)
        {
           if(start_value%i == 0)
           {
               System.err.printf ("No. Prime = %d \n", start_value);
               return false;
           }
        }
        return true;
    }


    public static void main(String args[])
    {
        Prime th1 = new Prime();
        Thread childOne = new Thread(th1);
        childOne.start();
        notPrime th2 = new notPrime();
        Thread childTwo = new Thread(th2);
        childTwo.start();   
    }
}

这是我按下run后的结果:

This is the result after I pressed run

这是按下再次运行后的结果:

This is the result after pressing again run

3 个答案:

答案 0 :(得分:1)

发生这种情况的原因是线程并行运行。当你创建一堆线程时,这些线程都会同时开始执行操作,并且看到哪些线程首先完成是一场竞赛。这不是确定性的,有时线程将以不同的顺序完成。

睡眠可能会改变这一点的原因是,睡眠会让你创建的主线先行开始。

答案 1 :(得分:0)

发生这种情况有两个原因:

  1. 您的主要方法未同步。
  2. 即使您同步prime方法,也会将ThreadDemo的不同实例传递给您的线程。在对象上获得锁。如果两个线程传递两个不同的ThreadDemo对象,每个线程将锁定自己的ThreadDemo实例,从而允许Threads并行运行。
  3. 您需要对代码进行一些更改,以确保线程使用相同的ThreadDemo。

    class NotPrimeRunnable implements Runnable {
        private ThreadDemo threadDemo;
        int number = 0;
    
        public NotPrimeRunnable(ThreadDemo threadDemo) {
            this.threadDemo = threadDemo;
        }
    
        public void run() {
            threadDemo.prime(number);
        }
    }
    
    class PrimeRunnable implements Runnable {
    
        private ThreadDemo threadDemo;
    
        public PrimeRunnable(ThreadDemo threadDemo) {
            this.threadDemo = threadDemo;
        }
    
        @Override
        public void run() {
            for (int i = 2; i <= 20; i++) {
                if (threadDemo.prime(i)) {
                    System.out.printf("Prime No.= %d \n", i);
                }
            }
        }
    
    }
    
    class ThreadDemo {
        public synchronized boolean prime(int start_value) {
            for (int i = 2; i < start_value; i++) {
                if (start_value % i == 0) {
                    System.err.printf("No. Prime = %d \n", start_value);
                    return false;
                }
            }
            return true;
        }
    
        public static void main(String args[]) {
            ThreadDemo runnableTask = new ThreadDemo();
            PrimeRunnable th1 = new PrimeRunnable(runnableTask);
            Thread childOne = new Thread(th1);
            childOne.start();
            NotPrimeRunnable th2 = new NotPrimeRunnable(runnableTask);
            Thread childTwo = new Thread(th2);
            childTwo.start();
        }
    }
    

    这将解决您的问题。

答案 2 :(得分:0)

维基百科将线程定义为:&#34;在计算机科学中,执行线程是可以由调度程序独立管理的最小程序指令序列&#34;。

调度程序是在SO内核中运行的软件模块,用于管理进程和线程执行。调度程序使用时分多路复用(如在多任务处理中)算法,以确保所有线程和进程都能够执行。在Windows,Mac OS和Linux等SO中,调度程序的特性之一是CPU在不同的软件线程之间切换。如维基百科中所述:&#34;此上下文​​切换通常经常发生,用户将线程或任务视为同时运行。&#34;

基于这些考虑因素,我们可以解释您的软件行为。非实时操作系统,如Windows和MAC OSx,以及许多Linux发行版都使用非确定性的调度算法,因此我们无法预测线程的执行顺序,那么每次执行时你很可能会获得关于文本输出顺序的不同结果。

当你在线程执行之间使用sleep时,似乎所选择的时间量足以在th2启动之前完全执行。因此输出以正确的顺序显示。