【问题标题】:Sleep current thread for a specific time将当前线程休眠特定时间
【发布时间】:2020-03-04 17:36:33
【问题描述】:

我正在尝试编写小型多线程程序。我想通过多个线程在不同的帧时间运行相同的进程。

我创建了一个输入文件,其中我对同一个进程有不同的名称,并且该进程应该运行的毫秒数。

T1|1000
T2|2000
T3|3000
T4|4000
T5|5000

Java 程序

package Test;

import java.io.*;

public class MultiProcess {


    public static void main(String[] args) throws IOException {

        BufferedReader br = new BufferedReader(new FileReader("/home/maria/Process.txt"));

        String st;
        while ((st = br.readLine()) != null) {

            String[] records = st.split("|");
            Thread tr = new ProcessExecution(records[0], Integer.parseInt(records[1]));
            tr.start();
        }

        br.close();
    }

    static class ProcessExecution extends Thread {

        int threadTime = 0;
        String processName;

        ProcessExecution(String processName, int x) {
            this.threadTime = x;
            this.processName = processName;

        }

        @Override
        public void run() {

            try {
                System.out.println("ProcessName: " + this.processName);
                Thread.sleep(this.threadTime);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

        }

    }

}

在上面的代码中,ProcessExecution 有不同的名字,它们来自文件,并且想要让当前运行的线程休眠特定的时间段,这也是来自文件。

我得到了这个奇怪的输出

ProcessName: T
ProcessName: T
ProcessName: T
ProcessName: T
ProcessName: T

什么是错以及如何实现?

谢谢

更新

似乎所有线程都在同时完成。它应该保持活跃到来自文件的毫秒数。怎么了?

【问题讨论】:

    标签: java multithreading


    【解决方案1】:

    “|”是一个特殊字符,需要转义。 将String[] records = st.split("|"); 替换为String[] records = st.split("[|]"); 即可。这里解释: https://javarevisited.blogspot.com/2017/01/how-to-split-string-based-on-delimiter-in-java.html

    您也可以将其替换为String[] records = st.split("\\|");

    【讨论】:

      【解决方案2】:

      当你这样做时

      String[] records = st.split("|");
      

      记录数组将有

      0 = "T"
      1 = "1"
      2 = "|"
      3 = "1"
      4 = "0"
      5 = "0"
      6 = "0"
      

      你应该这样做

      String[] records = st.split("\\|");
      

      作为 |是特殊字符

      【讨论】:

        【解决方案3】:

        正如其他人所指出的,您需要使用st.split("\\|") 来获取 T1 而不是 T。

        根据以正确顺序打印的正确值,例如,您希望首先休眠 1000 毫秒,然后才打印一条消息:

                try {
                    Thread.sleep(this.threadTime);
                    System.out.println("ProcessName: " + this.processName);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
        

        【讨论】:

        • 但是你不这么认为吗,代码运行的方式应该至少在我提到的几毫秒内保持活跃......?像你说的那样改变顺序有什么意义......?
        • 哦,是的,我错过了。您需要在打印之前进行睡眠,并且还需要等待 main() 中的所有线程终止。有关如何执行此操作的信息,请参阅stackoverflow.com/questions/7939257/…。我的建议首先睡眠来自假设您希望在每个线程分别在 1000、2000 等毫秒后打印语句。如果您先打印,所有打印语句将几乎立即以随机顺序显示,然后线程将只是休眠,除非被中断。
        • 但如果这是你要解决的真正问题,而不仅仅是家庭作业,我建议你学习线程池和 ExecutorService。
        【解决方案4】:

        你需要逃离管道:

        st.split("\\|");
        

        与我的 cmets 一起使用,这里有一个更好的整体解决方案:

        public class MultiProcess {
            private static final Logger LOGGER = Logger.getAnonymousLogger();
            public static void main(String[] args) throws IOException, InterruptedException {
        
            String [] values = new String[] {"T1|1000", "T2|2000", "T3|3000", "T4|4000", "T5|5000"}; 
            ExecutorService executor = Executors.newFixedThreadPool(5);
            for (String val : values) {
                String[] records = val.split("\\|");
                executor.execute(new ProcessExecution(records[0], Integer.parseInt(records[1])));
            }
            executor.shutdown();
        }
        
        static class ProcessExecution implements Runnable {
        
            int threadTime = 0;
            String processName;
        
            ProcessExecution(String processName, int x) {
                this.threadTime = x;
                this.processName = processName;
            }
        
            @Override
            public void run() {
               try {
                   Thread.sleep(this.threadTime);
                    LOGGER.info(String.format("ProcessName: %s", processName));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
        
            }
        
        }
        

        }

        【讨论】:

        • 它现在可以工作了。但是我的代码在尝试执行的方式上是否正确...?因为似乎所有线程都在同时完成。
        • 你的代码没问题。您遇到的是对控制台的线程访问。不要直接输出您的值,而是将它们保存到列表中,然后输出列表。然后你会看到正确的顺序。看看 CountDownLatch 以协助最终输出。
        • 但即使我让一个线程休眠 10 秒,整个代码也会在一秒内完成。我觉得有些不对劲。任何想法..?
        • 线程是一个非常复杂的主题。您必须了解的是,仅仅因为您告诉线程执行并不意味着它会立即执行。 JVM 仍然必须拥有启动进程的资源。启动一个线程只是告诉JVM“做这个工作”,它决定什么时候做这个工作。尝试使用 Logger 而不是 System.out 来执行输出,将类切换到实现 Runnable 而不是扩展 Thread 并查看 Executors 和 ExecutorService (Executors.newFixedThreadPool()) 应该可以满足您的需求。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-01-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多