使用两个线程,您应该打印“Hello World Hello World Hello World Hello World Hello World Hello World”。
在两个线程中,一个应该打印“Hello:”和另一个线程“World”。
我可以用不同的类来做到这一点,例如每个用于 hello 和 world 我也可以用内部类来做
有没有一种只有一个主类而没有内部类的方法?
使用两个线程,您应该打印“Hello World Hello World Hello World Hello World Hello World Hello World”。
在两个线程中,一个应该打印“Hello:”和另一个线程“World”。
我可以用不同的类来做到这一点,例如每个用于 hello 和 world 我也可以用内部类来做
有没有一种只有一个主类而没有内部类的方法?
有没有一种只有一个主类而没有内部类的方法?
当然。您可以传入字符串以打印到您的 Main 类中。当然,棘手的部分是协调线程,以便它们实际打印出来"HelloWorld"
而不是"WorldHello"
其他排列。线程将在不保证顺序的情况下并行运行。这就是线程程序的全部意义——它们异步运行。试图强制一个特定的单词输出否定了使用线程的目的。
<rant> 这对我来说是一个设计糟糕的计算机科学作业。使用线程编写的全部意义在于它们并行独立运行。协调通常发生在每个线程从工作队列中拉出然后将结果放入结果队列或其他东西时。任何时候你有一个线程程序需要协调这么多,你很可能不应该使用线程。</rant>
但是,由于每个人都对我之前的答案投了反对票,可能是因为它不能完美地解决他们的作业问题,所以我将添加一些逻辑来协调两个线程并吐出“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;
}
}
}
}
}
}
这看起来怎么样?没有线程对特定单词有特定的责任,但是使用几个Atomic
s 很容易确保线程处于同步状态。
该算法不依赖于只有两个线程 - 正如您所看到的,它仍然适用于任意数量的线程,在本例中为 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();
}
}
如果您希望 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()
方法来唤醒其他线程。
如果您不关心输出格式,请使用 Runnable 接口和您的首选实现。