Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 实现模拟线程#sleep() 背景_Java_Multithreading_Simulation - Fatal编程技术网

Java 实现模拟线程#sleep() 背景

Java 实现模拟线程#sleep() 背景,java,multithreading,simulation,Java,Multithreading,Simulation,我正在设计我的软件,以便能够轻松地执行单元测试。我有一个IClock接口,其中包括 IClock#等待(时间单位,长持续时间)。此方法将暂停当前线程一段时间(即1秒) IClock接口有两种实现方式: 模拟时钟:具有手动增加时钟中存储的时间的方法 RealClock:通过引用System.currentTimeMillis() 这是IClock#wait(…)的默认方法: 问题 目前我希望模拟单元测试的工作方式是 开始线程 等待所有线程完成或处于阻塞状态(我假设如果它们被阻塞,它们调用了IC

我正在设计我的软件,以便能够轻松地执行单元测试。我有一个
IClock
接口,其中包括
IClock#等待(时间单位,长持续时间)
。此方法将暂停当前线程一段时间(即1秒)

IClock
接口有两种实现方式:

  • 模拟时钟
    :具有手动增加时钟中存储的时间的方法
  • RealClock
    :通过引用
    System.currentTimeMillis()
这是
IClock#wait(…)
的默认方法:

问题 目前我希望模拟单元测试的工作方式是

  • 开始线程
  • 等待所有线程完成或处于阻塞状态(我假设如果它们被阻塞,它们调用了
    IClock#Wait(…)
  • 如果所有螺纹都已完成,请完成。否则,将模拟时钟时间增加一毫秒
  • 然而,真正发生的是:

  • 开始线程
  • 开始增加时间,即使线程没有第一次调用
    IClock#wait()
  • 因此,我需要做的是能够确定何时完成或阻止所有线程。虽然这可以通过
    Thread#getState()
    实现,但我更愿意采用一种更优雅的解决方案,并与
    ForkJoinPool
    一起使用

    完整代码

    模拟时钟
    在调用
    simulatedClock.incTimes()
    之前,各种线程似乎没有及时运行

    通常在多线程测试中,在开始时会有某种“会合”——允许所有线程在安全启动并运行后签入。如果您知道前面将有多少线程,那么使用
    CountDownLatch
    就很容易了

    例如,在
    Simulation.run()
    中:

    它保留了对
    倒计时闩锁的引用,以备以后使用

    当每个线程到达
    SimulatedClock.scheduleAt()
    时,它可以将闩锁向下计数一次:

    @Override
    public void scheduleAt(long millis, Runnable runnable)
    {
        if(millis < getTime())
        {
            throw new IllegalArgumentException("You are scheduling a task for before the current time!");
        }
        jobs.add(new Job(millis, runnable));
    
        countDownLatch.countDown();
    }
    

    我知道这并不能完全回答您的问题,但您不应该手动创建
    线程
    并使用现有的并发框架

    您可以这样做:

    public static void main(String[] args) {
        AtomicBoolean bool = new AtomicBoolean(false);
        ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
        ScheduledFuture<?> future = executorService.schedule(() -> bool.set(true), 5, TimeUnit.SECONDS);
        try {
            boolean b = future.get(100, TimeUnit.SECONDS);
        } catch (Exception e) {
            fail();
        }
        assertTrue(b);
    }
    

    首先,应该将IClock.wait重命名为IClock.sleep以避免混淆

    对于RealClock,此方法可以委托给Thread.sleep()

    对于模拟时钟,此方法可沿以下线路实施:

    void sleep(TimeUnit timeUnit, long dt) {
        final Object mon = new Object();
        scheduleIn(timeUnit, dt, 
            () -> {
                synchronized(mon) {
                   mon.notify();
                }
            });
        synchronized(mon) {
            try {
                mon.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }   
    }
    

    您可以修改它以抛出InterruptedException。

    如果您在Linux上运行,有一种秘密的方法。有一个实用程序(我记不起它的名字了,现在谷歌搜索也找不到),你可以用它来运行你的程序。任何时候,当你的程序调用导致睡眠的东西时,它都会截取它,并用零长度睡眠代替它。我认为它也开始在一天的时间上撒谎来补偿

    由于这适用于使用glibc编译的任何东西,包括JRE,因此它也适用于任何Java应用程序

    再次为未能提供有用的链接表示歉意-我将继续搜索我的书签/搜索,因为这听起来非常有用,我对自己记不起它的名字感到恼火

    编辑

    这样做的目的是,您不必在自己的程序中有两个单独的实现。用于睡眠的标准库调用在比程序更低的层被截获


    这不是我想的,但大致相同:。这似乎是在修补
    nanosleep()
    clock\u gettime()
    select()
    以及一些相关函数,因此它很有可能涵盖了基本功能

    但为什么你不能使用线程。睡眠?为什么需要在这里进行模拟?我希望单元测试尽可能快地运行。例如,我可能想模拟一个在现实世界中实际运行100秒但在模拟时可以在毫秒内运行的操作。为什么要手动创建线程并自己管理调度,而不是使用现有的
    ScheduledExecutor
    基础设施?需要明确的是,您希望确保测试中的
    Runnable
    s在
    n
    毫秒内完成,对吗?您在IClock#wait(…)中使用ReentrantLock()完全没有意义,因为每个调用线程都会得到一个单独的锁实例。”“我知道这并不能完全回答您的问题,但是您不应该手动创建线程并使用现有的并发框架。”:这是您的观点fact@gpasch这是Brian Goetz的一句话,所以这并不仅仅是我的观点
    @Test
    public void testSimpleAction()
    {
        AtomicBoolean atomicBoolean = new AtomicBoolean(false);
        Simulation simulation = new Simulation();
        simulation.add(new DealyedAction((TimeUnit.SECONDS, 5) -> atomicBoolean.set(true)));
        simulation.run(TimeUnit.SECONDS, 100);
        Assert.assertTrue(atomicBoolean.get());
    }
    
        simulatedClock.init(new CountDownLatch(actions.size()));
    
    @Override
    public void scheduleAt(long millis, Runnable runnable)
    {
        if(millis < getTime())
        {
            throw new IllegalArgumentException("You are scheduling a task for before the current time!");
        }
        jobs.add(new Job(millis, runnable));
    
        countDownLatch.countDown();
    }
    
    public void incTimes(long times, long dt)
    {
        countDownLatch.await();
    
        long init = getTime();
        ...
    
    public static void main(String[] args) {
        AtomicBoolean bool = new AtomicBoolean(false);
        ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
        ScheduledFuture<?> future = executorService.schedule(() -> bool.set(true), 5, TimeUnit.SECONDS);
        try {
            boolean b = future.get(100, TimeUnit.SECONDS);
        } catch (Exception e) {
            fail();
        }
        assertTrue(b);
    }
    
    interface Clock {
        Future<?> scheduleAt(long millis, Runnable r);
    }
    
    class SchedulerService implements Clock {
        ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
    
        public Future<?> scheduleAt(long millis, Runnable r) {
            Instant scheduleTime = Instant.ofEpochMilli(millis);
            Instant now = Instant.now();
            if (scheduleTime.isBefore(now)) {
                throw new IllegalArgumentException("You are scheduling a task for before the current time!");
            }
            long delay = scheduleTime.minus(now).toEpochMilli();
            return executorService.schedule(r, delay, TimeUnit.MILLISECONDS);
        }
    }
    
    void sleep(TimeUnit timeUnit, long dt) {
        final Object mon = new Object();
        scheduleIn(timeUnit, dt, 
            () -> {
                synchronized(mon) {
                   mon.notify();
                }
            });
        synchronized(mon) {
            try {
                mon.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }   
    }