我是多线程新手,了解wait,notify和notifyAll的功能。我想要一个接一个地执行三个线程并从A到Z打印字母。 我尝试了下面的代码,它似乎也工作,但我怀疑这是否是解决问题的最佳方法。还有其他方法,我可以让它更简单,更好吗?似乎我的代码的某些部分正在重复。
package demo.threading;
class Flags {
boolean flagA = true;
boolean flagB = false;
boolean flagC = false;
}
class Container {
Flags flags = new Flags();
int charVal = (int) 'A';
void producer1() {
try {
while (charVal <= (int) 'Z') {
synchronized (this) {
if (!flags.flagA)
wait();
else {
System.out.println(Thread.currentThread().getName() + " Produced : " + (char) charVal);
flags.flagA = false;
flags.flagB = true;
charVal++;
notifyAll();
Thread.sleep(1000);
}
}
}
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
void producer2() {
try {
while (charVal <= (int) 'Z') {
synchronized (this) {
if (!flags.flagB)
wait();
else {
System.out.println(Thread.currentThread().getName() + " Produced : " + (char) charVal);
flags.flagB = false;
flags.flagC = true;
charVal++;
notifyAll();
Thread.sleep(1000);
}
}
}
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
void producer3() {
try {
while (charVal <= (int) 'Z') {
synchronized (this) {
if (!flags.flagC)
wait();
else {
System.out.println(Thread.currentThread().getName() + " Produced : " + (char) charVal);
flags.flagC = false;
flags.flagA = true;
charVal++;
notifyAll();
Thread.sleep(1000);
}
}
}
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
}
public class Main {
public static void main(String[] args) {
Container container = new Container();
Thread t1 = new Thread(() -> container.producer1(), "Thread 1");
Thread t2 = new Thread(() -> container.producer2(), "Thread 2");
Thread t3 = new Thread(() -> container.producer3(), "Thread 3");
t1.start();
t2.start();
t3.start();
}
}
输出应为:
Thread 1 Produced : A
Thread 2 Produced : B
Thread 3 Produced : C
Thread 1 Produced : D
Thread 2 Produced : E
Thread 3 Produced : F
答案 0 :(得分:4)
如前所述,如果你想要一个接一个地做到这一点&#34;,你实际上并不需要多个线程。但是,您可以使用Semaphore
:
int numberOfThreads = 3;
Semaphore semaphore = new Semaphore(1);
for (int i = 1; i <= numberOfThreads; i++) {
new Thread(() -> {
try {
semaphore.acquire();
for (char c : "ABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray()) {
System.out.println(Thread.currentThread().getName()
+ " produced: " + c + ".");
}
} catch (InterruptedException e) {
// NOP
} finally {
semaphore.release();
}
}, "Thread " + i).start();
}
我建议探索自Java 5以来可用的java.util.concurrent
。与Java的低级并发原语(如{1)相比,它可以帮助您保持并发代码简洁明了。 }和wait
。如果您真的对该主题感兴趣,Brian Goetz's "Java Concurrency in Practice"是必读的。
修改强>
notify
答案 1 :(得分:0)
package demo.thread;
public class ABCPuzzle {
private static class RunnableImpl implements Runnable {
private String nextThread;
private ExecServ execServ;
public RunnableImpl(ExecServ execServ, String nextThread) {
this.execServ = execServ;
this.nextThread = nextThread;
}
@Override
public void run() {
String threadName = Thread.currentThread().getName();
synchronized (execServ) {
try {
while (true) {
if (execServ.key > 'Z')
break;
if (threadName.equals(execServ.current)) {
System.out.println(threadName + " consuming " + execServ.key);
Thread.sleep(1000);
execServ.key++;
execServ.current = nextThread;
execServ.notifyAll();
} else
execServ.wait();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
private static class ExecServ {
private String current, next;
private char key = 'A';
}
public static void main(String[] args) {
ExecServ execServ = new ExecServ();
execServ.current = "t1";
Thread t1 = new Thread(new RunnableImpl(execServ, "t2"), "t1");
Thread t2 = new Thread(new RunnableImpl(execServ, "t3"), "t2");
Thread t3 = new Thread(new RunnableImpl(execServ, "t4"), "t3");
Thread t4 = new Thread(new RunnableImpl(execServ, "t1"), "t4");
t1.start();
t2.start();
t3.start();
t4.start();
}
}
输出:
t1 consuming A
t2 consuming B
t3 consuming C
t4 consuming D
t1 consuming E
t2 consuming F
t3 consuming G
t4 consuming H
t1 consuming I
t2 consuming J