如何在java中设置线程的时间?

时间:2013-10-16 18:59:22

标签: java multithreading

我正在实现一个简单的多线程示例,其中线程1在每1000毫秒后打印PING,线程2在每2000毫秒后打印PONG。

public class T extends Thread 
{
public void run()
{
int i =10;
while(i>0)
{
    if(Thread.currentThread().getName().equals("T1"))
    {
        System.out.println("\nPING");
        try {Thread.sleep(1000);} 
        catch (InterruptedException e) {e.printStackTrace();}   
    }
    else if (Thread.currentThread().getName().equals("T2"))
    {
        System.out.println("\nPONG");
        try {Thread.sleep(2000);} 
        catch (InterruptedException e) {e.printStackTrace();}
    }
i--;
}
}

public static void main(String[] args) 
{
    Thread t1 = new T();
    Thread t2 = new T();
    t1.setName("T1");
    t2.setName("T2");
    t1.start();
    t2.start();
}
}

但是输出就像::

PONG

PING

PING

PING

PONG

PING

PING

PONG

PING

PING

PONG

PING

PING

PONG

PING

PONG

PONG

PONG

PONG

PONG

但我的预期输出应该是

PING
PING
PONG
PING
PING
PONG
PING
PING
PONG.....

代码中应该进行哪些更改?

6 个答案:

答案 0 :(得分:4)

假设两个线程都在时间0开始,并且无论什么(线程调度)原因PONG首先启动。

PONG (now wait 2000) // 0 has elapsed
PING (now wait 1000) // 0 has elapsed
PING (now wait 1000) // 1000 has elapsed
PING (now wait 1000) // 2000 has elapsed
PONG (now wait 2000) // 2000 has elasped
... and so on

如果您想要PING s然后PONG,请考虑使用一些通知机制(信号量,coutdown锁存器等)。不要依赖sleep()

答案 1 :(得分:2)

来自Thread.sleep的文档:

  

导致当前正在执行的线程进入休眠状态(暂时停止   执行)指定的毫秒数,受制于   系统定时器和调度程序的精度和准确度。

如果你想确保线程打印 PING 运行两次,然后等待另一个线程打印 PONG (它依次等待两个PINGS继续),你需要相互同步线程。请参阅Object.waitObject.notify

编辑:这是一个同步的版本(它很乱,但问题中的原文也是如此; P):

public class T extends Thread
{
    //Static object to synchronize on... bad practice but this is just an example anyway
    static Object synchOnMe = new Object();

    public void run()
    {
        int i = 10;
        while(i > 0)
        {
            if(Thread.currentThread().getName().equals("T1"))
            {               
                System.out.println("PING");
                try
                {
                    Thread.sleep(1000);

                    //Synchronize on every second time (ie. wait for PONG)
                    if((i + 1) % 2 == 0)
                    {
                        synchronized(synchOnMe)
                        {
                            synchOnMe.notify();
                            synchOnMe.wait();
                        }
                    }                   
                }
                catch(InterruptedException e)
                {
                    e.printStackTrace();
                }

            }
            else if(Thread.currentThread().getName().equals("T2"))
            {
                try
                {
                    //Synchronize every time (ie. wait for PING)
                    synchronized(synchOnMe)
                    {
                        synchOnMe.wait();
                        System.out.println("PONG");
                        synchOnMe.notify();
                    }

                    Thread.sleep(2000);
                }
                catch(InterruptedException e)
                {
                    e.printStackTrace();
                }


            }
            i--;
        }

        //One last notify to release the other thread waiting
        synchronized(synchOnMe)
        {
            synchOnMe.notify();
        }

    }

    public static void main(String[] args)
    {
        Thread t1 = new T();
        Thread t2 = new T();
        t1.setName("T1");
        t2.setName("T2");
        t1.start();
        t2.start();
    }
}

输出:

PING
PING
PONG
PING
PING
PONG
PING
PING
PONG
PING
PING
PONG
PING
PING
PONG

答案 2 :(得分:0)

答案 3 :(得分:0)

移动

System.out.println("\nPING or PONG");

之前的Thread.sleep()

或在启动时在踏板之间添加Thread.sleep()。

t1.start();
Thread.sleep(100);
t2.start();

(但我不喜欢第二种解决方案)

尽管这不是一个专业的解决方案,它应该可以工作大约30次迭代。 之后,由于它们没有正确同步,因此不再适用。

答案 4 :(得分:0)

首先,您应该使用for循环而不是while循环。它使你的意图更加清晰。其次,您需要了解线程不能保证按照启动它们的顺序执行。所有保证的是内核将根据底层操作系统的工作方式以及内核将等待的方式开始为线程分配时间片。 em>至少指定线程休眠的时间(如果内核支持合并线程,有时会更少)。

这意味着T1实际上可以在一轮中等待996 ms而T2可以等待2026 ms用于另一轮。例如,当我运行此代码时,我得到以下输出:
PING
PONG
PING
PING
PONG
PING
PING
PONG
PING
PONG
PING
PING
PONG
PING
PING
PONG
PONG
PONG
PONG
PONG

有点乱。现在,在许多多线程应用程序中,当线程不相互依赖时,这是可以的。但是,如果您希望输出按照预期的方式排列,那么就像其他答案所示,您需要使用wait()和notify()。

例如,有T1启动,然后T1启动T2。 T2应该在执行时立即等待,然后T1应该在每次PING时通知T2。 T2然后可以计算收到通知的次数,每当计数均匀时,它可以输出PONG。

我将实施作为练习开放。

答案 5 :(得分:0)

一般情况下,在这种情况下,不可能有确定性的输出(除非你是一些奇特的实时技术)。这是由于OS管理线程的方式。线程结束的事实并不意味着它会立即收到CPU时间。

对线程执行进行确定性排序的唯一方法是使用它们之间的同步。使用谷歌了解更多,因为这是非常复杂的事情。