【问题标题】:Multi threaded Hello World多线程 Hello World
【发布时间】:2013-04-12 21:50:41
【问题描述】:

使用两个线程你应该打印“Hello World Hello World Hello World Hello World Hello World Hello World”。

在两个线程中,一个线程应该打印“Hello:”,另一个线程应该打印“World”。

我可以使用不同的类来做到这一点,例如 hello 和 world 各一个 我也可以用内部类来做到这一点

有没有办法做到只有一个主类,没有内部类?

【问题讨论】:

  • 是的;在类中使用一个字段并创建两个实例。
  • 将您的班级设为Runnable,您可以将String 传递给该班级。

标签: java multithreading


【解决方案1】:

有没有办法做到只有一个主类,没有内部类?

当然。您可以传入字符串以打印到您的 Main 类中。当然,棘手的部分是协调线程,以便它们实际打印出"HelloWorld" 而不是"WorldHello" 或其他排列。线程将在不保证顺序的情况下并行运行。这就是线程程序的全部意义——它们异步运行。试图强制一个特定的单词输出否定了使用线程的目的。

这对我来说是一个设计糟糕的计算机科学作业。使用线程编写的全部意义在于它们并行独立运行。协调通常发生在每个线程从工作队列中拉出然后将结果放入结果队列或其他东西时。任何时候你有一个线程程序需要协调这么多,你很可能不应该使用线程。

但是,由于每个人都反对我之前的答案,可能是因为它不能完美地解决他们的作业问题,所以我将添加一些逻辑来协调两个线程并吐出“Hello World...”。

这两个线程需要能够锁定某些东西,相互发出信号,并知道它们应该何时等待或打印。所以我将添加一个boolean printHello 并锁定一个传入的通用锁对象:

public class HelloWorld implements Runnable {

    private static boolean printHello = true;

    private final String toPrint;
    private final boolean iPrintHello;
    private final Object lock;

    public static void main(String[] args) {
        final Object lock = new Object();
        // first thread prints Hello
        new Thread(new HelloWorld("Hello ", true, lock)).start();
        // second one prints World
        new Thread(new HelloWorld("World ", false, lock)).start();
    }

    public HelloWorld(String toPrint, boolean iPrintHello, Object lock) {
        this.toPrint = toPrint;
        this.iPrintHello = iPrintHello;
        this.lock = lock;
    }

    @Override
    public void run() {
        // don't let it run forever
        for (int i = 0; i < 1000 && !Thread.currentThread().isInterrupted(); ) {
            // they need to synchronize on a common, constant object
            synchronized (lock) {
                // am I printing or waiting?
                if (printHello == iPrintHello) {
                    System.out.print(toPrint);
                    // switch the print-hello to the other value
                    printHello = !printHello;
                    // notify the other class that it can run now
                    lock.notify();
                    i++;
                } else {
                    try {
                        // wait until we get notified that we can print
                        lock.wait();
                    } catch (InterruptedException e) {
                        // if thread is interrupted, _immediately_ re-interrupt it
                        Thread.currentThread().interrupt();
                        return;
                    }
                }
            }
        }
    }
}

【讨论】:

  • cmets 很有帮助。 lock 传入的任何线程对象都会同步到它,这意味着它(lock)将管理线程何时可以运行。如果有 3 个线程呢?有没有办法我也可以指定线程?我查看了notify() 文档,它说默认选择下一个线程,并且没有重载方法。
  • 如果有超过 1 个线程,您可以调用 notifyAll(),它们都会醒来,看看是否应该打印 @Abdul。我真的很讨厌使用notifyAll(),因为通常任何线程都应该能够进行处理,但在这个奇怪的例子中,它可以工作。
【解决方案2】:

这看起来怎么样?没有线程对特定单词有特定的责任,但使用几个Atomics 很容易确保线程处于同步状态。

该算法不依赖于只有两个线程 - 正如您所见,它仍然适用于任意数量的线程,在本例中为 42 个。只需 2 个,甚至 1 个,它仍然可以正常工作。

public class HelloWorld implements Runnable {
  // The words.
  private final String[] words;
  // Which word to print next.
  private final AtomicInteger whichWord;
  // Cycles remaining.
  private final AtomicInteger cycles;

  private HelloWorld(String[] words, AtomicInteger whichWord, AtomicInteger cycles) {
    // The words to print.
    this.words = words;
    // The Atomic holding the next word to print.
    this.whichWord = whichWord;
    // How many times around we've gone.
    this.cycles = cycles;
  }

  @Override
  public void run() {
    // Until cycles are complete.
    while ( cycles.get() > 0 ) {
      // Must transit from this word
      int thisWord = whichWord.get();
      // to the next word.
      int nextWord = thisWord + 1;
      // Are we cycling?
      boolean cycled = false;
      if ( nextWord >= words.length ) {
        // We cycled!
        cycled = true;
        // Back to zero.
        nextWord = 0;
      }
      // Grab hold of System.out to ensure no race there either.
      synchronized ( System.out ) {
        // Atomically step the word number - must still be at thisWord for the step calculations to still be correct.
        if ( whichWord.compareAndSet(thisWord, nextWord)) {
          // Success!! We are the priveliged one!
          System.out.print(words[thisWord]);
          // Count the cycles.
          if ( cycled ) {
            // Just step it down.
            cycles.decrementAndGet();
          }
        }
      }
    }
  }

  public static void test() throws InterruptedException {
    // The words to print.
    String [] words = {"Hello ", "world. "};
    // Which word to print next (start at 0 obviously).
    AtomicInteger whichWord = new AtomicInteger(0);
    // How many cycles to print - 6 as specified.
    AtomicInteger cycles = new AtomicInteger(6);
    // My threads - as many as I like.
    Thread [] threads = new Thread[/*2*/42];
    for ( int i = 0; i < threads.length; i++ ) {
      // Make each thread.
      threads[i] = new Thread(new HelloWorld(words, whichWord, cycles));
      // Start it.
      threads[i].start();
    }
    // Wait for them to finish.
    for ( int i = 0; i < threads.length; i++ ) {
      // Wait for completion.
      threads[i].join();
    }
  }

  public static void main(String args[]) throws InterruptedException {
    System.out.println("HelloWorld:Test");
    test();
  }

}

【讨论】:

  • 呃,哇。这当然是一种方法。不过,您错过了加入磁通电容器。 :-)
  • @Gray - 添加磁通电容器会使Atomics 过载。
【解决方案3】:
  1. 如果您希望 T1 打印“Hello”,T2 打印“World”,并且您的预期结果是“Hello World Hello World Hello World Hello World Hello World Hello World”

    T1 先启动,T2 由 T1 调用,否则输出“World Hello Hello Hello World”。

    我建议自定义一个reader/writer或者producer/consumer结构,使用notify()或者notifyAll()方法唤醒其他线程。

  2. 如果您不关心输出格式,请使用 Runnable 接口和您的首选实现。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-03-14
    • 1970-01-01
    • 1970-01-01
    • 2014-05-01
    • 1970-01-01
    • 2015-05-04
    • 2012-01-04
    • 2014-10-15
    相关资源
    最近更新 更多