多线程的Hello World

5

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

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

我可以使用不同的类来实现,例如分别为hello和world创建一个类,也可以使用内部类来实现。

是否有一种方法可以只使用一个主类而没有内部类?


1
使用类中的字段并创建两个实例。 - SLaks
1
将你的类设为“Runnable”,这样你就可以传递一个“String”参数。 - Sotirios Delimanolis
3个回答

5
有没有一种方法,只有一个主类而没有内部类?
当然。您可以将要打印的字符串传递到Main类中。当然,棘手的部分是协调线程以使它们实际上打印出“HelloWorld”,而不是“WorldHello”或其他排列组合。线程将并行运行,并且不存在任何顺序保证。这就是使用线程程序的全部目的-它们异步运行。试图强制输出特定单词会否定使用线程的目的。
愤怒地说,这对我来说似乎是一个设计不良的计算机科学作业。使用线程编写的整个程序之所以重要,是因为它们在并行独立地运行。当每个线程从工作队列中拉取,然后将结果放入结果队列或类似的东西时,通常会发生协调。如果您有一个需要这么多协调的线程程序,那么您很可能不应该使用线程。
但是,由于每个人都在投票反对我的先前答案,可能是因为它不能完美地解决他们的家庭作业问题,我将添加一些逻辑来协调两个线程并吐出“Hello World...”。
两个线程需要能够锁定某些内容,相互发信号,并知道何时应等待或打印。因此,我将添加一个布尔值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;
                    }
                }
            }
        }
    }
}

注释非常有用。任何传递了lock的线程对象都会被它同步,这意味着它(lock)将管理线程何时可以运行。如果有三个线程怎么办?我能指定线程吗?我查看了notify()文档,它说下一个线程是默认选择的,并且没有重载方法。 - Honinbo Shusaku
如果有多个线程,您可以调用notifyAll(),它们都会被唤醒并查看是否应该打印@Abdul。我真的不喜欢使用notifyAll(),因为通常任何线程都应该能够进行处理,但在这个奇怪的例子中,它起作用了。 - Gray

1
这看起来怎么样?没有线程对特定单词负责,但使用几个Atomic可以轻松确保线程同步。该算法不依赖于只有两个线程-正如您所看到的,在任意数量的线程(本例中为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
1
@Gray - 添加一个通量电容器会导致Atomics超载。 - OldCurmudgeon

0
  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"。

    我建议使用自定义的读者/写者或生产者/消费者结构,使用notify()notifyAll()方法唤醒其他线程。

  2. 如果你不关心输出格式,可以使用Runnable接口和你喜欢的实现方式。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接