使用两个线程,您应该打印“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创建一个类,也可以使用内部类来实现。
是否有一种方法可以只使用一个主类而没有内部类?
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 ShusakunotifyAll()
,它们都会被唤醒并查看是否应该打印@Abdul。我真的不喜欢使用notifyAll()
,因为通常任何线程都应该能够进行处理,但在这个奇怪的例子中,它起作用了。 - GrayAtomic
可以轻松确保线程同步。该算法不依赖于只有两个线程-正如您所看到的,在任意数量的线程(本例中为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();
}
}
Atomic
s超载。 - OldCurmudgeon如果你想让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接口和你喜欢的实现方式。