Thread.sleep(time)不能按我需要的方式工作。我需要更好的东西

时间:2018-04-18 18:29:13

标签: java

我是丹麦的一名学生,正在尝试制作一个学校项目。我现在正在做的是一个读取器类,它接收一个字符串然后逐个字母地打印出来。

我做了一些研究,发现Thread.sleep(time)完全按照我的要求去做。 但是在我使用它之后我发现它无法正常工作!我试着再研究一下,找到了一个名为ThreadPoolExecutor的东西,但我可以弄清楚它是如何起作用的。

我的读者:

public class TextReader {

    // Print method to print word by word from a string
    public void wordByWord(String text) throws InterruptedException {
        String[] words = text.split(" ");
        for (int i = 0; i < words.length; i++) {
            System.out.print(words[i] + " ");
            Thread.sleep(250);
        }
    }

    // Print method to print letter by letter from a string
    public void letterByLetter(String text) throws InterruptedException {
        String[] words = text.split(" ");
        for (int i = 0; i < words.length; i++) {
            String word = words[i] + " ";
            char[] letters = (word.toCharArray());
            for (int j = 0; j < letters.length; j++) {
                System.out.print(letters[j]);
                Thread.sleep(250); //so it does not print all the letters at once
            }
        }
    }
}

Thread.sleep(time)在我的情况下不起作用的原因是因为我需要打印到控制台并使用Thread.sleep(time)它不像瀑布一样打印。它打印出我想要分解的字符串(时间低于250毫秒)或一些字母一次(250毫秒)或者只是如此慢,我无法看到它......(超过250毫秒)。我需要它快速平稳地运行!所以看起来有人在写它。

4 个答案:

答案 0 :(得分:2)

我想我成功地重新创建了你的问题。每次延迟低于 205 ms 似乎都会导致更新问题。有时单词/字母不会出现,但在下一个时间间隔内会出现多个单词/字母。

这似乎是控制台I / O性能的限制(See this answer)。你真的无法做到这一点。如果您希望以这样的短暂,最小延迟输出文本,则需要编写自己的GUI(例如JavaFX)。这可能会解决性能问题。

以不同延迟输出

205 ms

Desired output, but too slow (205ms)

190 ms

Undesired, "unsmooth" output (190ms)

答案 1 :(得分:1)

你正在做的是让一个线程在那个时候睡觉。这意味着在此之后线程将被解除阻塞,但是您没有考虑从另一个线程切换上下文的开销。 What you want is something more like this

答案 2 :(得分:1)

线程的sleep方法需要几毫秒来停止执行当前线程达指定的毫秒数。如果它很慢,你可以传递较少的MS,如果它很快,那么你可以增加时间。所以你可以根据需要进行调整。

ExecutorFramework是另一回事。 这是一种将可运行任务提交给ExecutorFramework管理的线程的方法。

答案 3 :(得分:0)

尝试ScheduledExecutorService方法,似乎工作正常。有一些优化要做,有些箍要跳过等待预定的打印完成,但它似乎没有显示滞后(在我试过的两个控制台中 - Eclipse输出和Windows Bash )。

public class Output {
    public static void main(String[] args) {
        String toPrint = "Hello, my name is Voldemort, but few call me that.";
        StringPrinter printer = new StringPrinter();
        printer.print(toPrint, Output::byCharacter, 30);
        System.out.println();
        printer.print(toPrint, Output::byWord, 150);
    }

    private static List<String> byWord(String toSplit) {
        Iterable<String> it = () -> new Scanner(toSplit);
        return StreamSupport.stream(it.spliterator(), false).map(s -> s + " ").collect(Collectors.toList());
    }

    private static List<String> byCharacter(String toSplit) {
        return toSplit.chars().mapToObj(i -> "" + (char) i).collect(Collectors.toList());
    }
}

class StringPrinter implements Runnable {
    // using an array to be most efficient
    private String[] output;
    private int currentIndex;

    // the service providing the milliseconds delay
    private ScheduledExecutorService printExecutor;

    public void print(String toOutput, Function<String, List<String>> split, int delay) {
        if (printExecutor != null) {
            throw new IllegalStateException();
        }
        printExecutor = Executors.newSingleThreadScheduledExecutor();
        List<String> list = split.apply(toOutput);
        output = list.toArray(new String[list.size()]);
        currentIndex = 0;

        printExecutor.scheduleWithFixedDelay(this, 0, delay, TimeUnit.MILLISECONDS);

        // wait until output has finished
        synchronized (this) {
            while (printExecutor != null)
                try {
                    wait(); // wait for printing to be finished
                } catch (InterruptedException e) {}
        }
    }

    @Override
    public void run() {
        if (currentIndex < output.length) {
            System.out.print(output[currentIndex++]);
        } else {
            // mark this print run as finished
            printExecutor.shutdown();
            printExecutor = null;
            synchronized (this) { notifyAll(); }
        }
    }
}