【问题标题】:high resolution timer in javajava中的高分辨率计时器
【发布时间】:2012-10-29 20:56:21
【问题描述】:

我想用 Java 模拟 TCP。

为此,我有多个线程,例如每个 TCP 连接的发送者和接收者线程。

我的问题是,我想暂停(如 Thread.sleep())线程微秒时间间隔。这样我就可以模拟流控制,发送者线程在发送下一个数据包之前会阻塞几微秒,同时CPU可以被接收和数据处理线程使用。但我找不到任何执行 sleep() 或 wait() 以实现微秒或纳秒分辨率的方法。如何在 Java 中以微秒或纳秒的分辨率阻塞(暂停)线程?

我找到了 System.nanoTime() 方法,但没有在指定的微秒或纳秒内阻塞线程的方法。如果有这样的方法,请告诉我。 System.nanoTime() 只是给出了以纳秒为单位的相对时间间隔。

我可以使用System.nanoTime()在busy-loop的线程中执行纳秒延迟,但这会浪费CPU,这本来可以用于接收数据线程或处理线程。

另一个令人困惑的问题:

通过上网,我发现 Thread.sleep() 或 wait() 方法在 Windows 系统中阻塞至少指定的毫秒或 10 毫秒的倍数,以较短者为准,没有线程中断。但是当我运行示例示例时,我发现了非常不同的结果。就像线程的睡眠时间少于指定的毫秒数。有些线程给了我 100 微秒的睡眠时间。测量的时间是否有误? System.nanoTime() 不是那么准确吗?请参见下面的示例,其中我得到了非常不同的结果。线程优先级也没有给出预测结果。

public class MyClass {
    public static void main(String args []){
        Runnable r = new Runnable() {
            public void run() {
                long s = System.nanoTime();
                //Thread.yield();  // Try for yield, need to check - in how much time high priority thread will be scheduled back after yielding
                try{
                    Thread.sleep(1);
                }catch(Exception e){

                }
                long e = System.nanoTime() - s;
                System.out.println(Thread.currentThread().getName()+e);
            }
        };

        Thread t1 = new Thread(r, "Thread T1: ");
        t1.setPriority(Thread.MAX_PRIORITY);
        t1.start();

        Thread t2 = new Thread(r, "Thread T2: ");
        t2.setPriority(Thread.MIN_PRIORITY);
        t2.start();

        Thread t3 = new Thread(r, "Thread T3: ");
        t3.setPriority(Thread.NORM_PRIORITY);
        t3.start();

        Thread t4 = new Thread(r, "Thread T4: ");
        t4.setPriority(Thread.MAX_PRIORITY);
        t4.start();

        long s = System.nanoTime();
        try{
            Thread.sleep(1);
        }catch(Exception e){

        }
        long e = System.nanoTime() - s;
        System.out.println("Main: "+e);
    }
}

在我的带有 Intel Core i5、2.53 GHz 的系统中,我在多次运行中得到了类似下面的输出。 *下面输出中的换行符没有在这篇文章中打印出来,我已经从控制台复制了输出,但是它在我的控制台中给了我换行符,这没问题。

线程 T1:736682 线程 T3:700212 线程 T2:478559 主营:548257 线程 T4:458299

第二次运行 -

线程 T3:27555 线程 T2:139799 线程 T1:152361 主营:93199 线程 T4:29986

第三轮 -

线程 T4:724525 线程 T2:1050319 主营:752486 线程 T1:941316 线程 T3:1000883

第四轮 -

线程 T1:174243 线程 T2:166543 线程 T3:1005745 主营:1023170 线程 T4:915787

在上面的运行中,我得到了微秒阻塞。 :O

请指导我。

为长篇道歉。感谢您阅读整篇文章。

【问题讨论】:

  • Thread中有一个sleep方法,可以将nanos作为参数。 'Thread.sleep(int mili, int nano)' - 我认为你不能细化到微秒。
  • 我的系统是:Intel Core i5,2.53 GHz,Windows 7 Enterprise OS。
  • 嗨 Jiman,Thread.sleep(int mili, int nano) 不是将睡眠时间舍入到毫秒时间吗?
  • @user1508907 很难看出这样做会有什么意义,但它“取决于系统计时器和调度程序的精度和准确性。线程不会失去任何监视器的所有权"。
  • 运行你的代码我得到每个线程 1 到 2 毫秒的结果...

标签: java multithreading networking concurrency


【解决方案1】:

注意Thread.sleep(timeout) 保证Thread 将休眠至少 毫秒(取决于底层系统的精度),但它可能会休眠更长时间。

有一个Thread.sleep(millis, nanos),但精度也不是很好。正如@TimBender 在下面指出的那样,在OpenJDK 6-b14 中,它甚至通过舍入和调用Thread.sleep(millis) 来实现这一点。因此,可以相当肯定地说,在任何 Java 实现中,您都不能依赖它在准确的时间间隔内休眠。

【讨论】:

  • 查看后一种方法的实现,它只是将所有内容转换为最接近的毫秒(向上舍入)。
  • @TimBender:哇,我知道精度很差,但这比我想象的还要糟糕。
  • @TimBender 这无疑是特定于实现的,将来可能会改变。确切的合同在 javadoc 中指定。
  • Keppil, ((注意 Thread.sleep(timeout) 保证线程将休眠至少 timeout ms (取决于底层系统的精度),但它可能会休眠更长时间。))那么为什么我的输出中的睡眠时间少于 1 毫秒。使用 System.nanoTime() 测量的时间
  • 啊,另一种方法是尝试使用Condition.awaitNanos,但我无法验证它是否会以更高的精度返回。
【解决方案2】:

您受制于操作系统线程调度程序,对此您无能为力。仅仅因为你睡了很短的时间并不意味着调度程序会在它完成睡眠后立即唤醒你的线程。而且线程优先级只是一个提示,没有任何保证。

【讨论】:

    【解决方案3】:

    试试这个:

    Thread.sleep(0, 250); // sleep 250 nanoseconds
    

    【讨论】:

      【解决方案4】:

      我相信你想要使用的是Condition.awaitNanos,但是我找不到任何确凿的证据来证明这将在接近请求的时间时以高精度返回。

      或者,您可以传递一个略小于所需总时间的“awaitNanos”时间,然后在循环中“实时等待”直到总时间过去。

      【讨论】:

      • Condition 是一个接口。您建议使用哪种实施方式? ReentrantLock.newCondition 例如使用 LockSupport.parkNanos() 在某些情况下可以立即返回。
      • 老实说,使用Condition 完全是一种黑客行为。最好查看属于ReentrantLockCondition 的实现,然后“借用”代码模式以进行自定义高精度等待。阅读 javadoc,Condition.awaitNanos 的优势在于它将返回剩余的纳秒,因此可以根据需要使用循环等待更多时间。同样,我可能会借一些东西,然后通过实时等待进行创新。
      猜你喜欢
      • 1970-01-01
      • 2010-09-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-04-02
      • 2011-10-31
      • 1970-01-01
      相关资源
      最近更新 更多