我无法解决一个线程在等待另一个问题的麻烦(即使在查看了几个问题后也是如此)。这是我要尝试的操作:我希望一个线程(称为子线程)在外循环下进行2次迭代打印10次。然后另一个(boss线程)在外循环下进行2次迭代打印100次,前提是子线程位于第一位。它看起来像这样:
Sub Thread- iter = 1
Sub Thread- iter = 2
...
Sub Thread- iter = 10
Boss Thread- iter = 1
Boss Thread- iter = 2
...
Boss Thread- iter = 100
此子线程和老板线程的打印顺序将连续2次(外循环)。
我的实现产生了无法预料的结果,即它打印出子线程的第一次迭代10次然后停止在那里,或者它很少打印出所有语句并遍历内循环和外循环。我使用wait()
和notify()
启用线程之间的通信。我不确定将synchronized
块放置在错误的位置还是误用了wait()
和notify()
对。这是代码:
public class Main {
public static void main(String[] args) {
Main ic = new Main();
Thread t1 = new Thread(ic.new Th1(), "Boss Thread-");
Thread t2 = new Thread(ic.new Th2(), "Sub Thread-");
t2.start();
t1.start();
}
// Boss Thread
private class Th1 implements Runnable {
@Override
public void run() {
System.out.println("TH1 RUNS FIRST");
synchronized (Main.class) { // lock outside of outer loop so
// boss thread can pick up the next iteration
for (int i = 0; i < 2; i++) {
// wait, let the sub-thread run first
try {
Main.class.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
// print iterations
for (int j = 0; j < 100; j++) {
System.out.println(Thread.currentThread().getName() + " iter = " + (j + 1));
}
System.out.println("end of boss outer----------------------" + (i + 1));
// wake up sub-thread and let it knows inner-iteration finished
Main.class.notify();
}
}
}
}
// Sub Thread
private class Th2 implements Runnable {
@Override
public void run() {
for (int i = 0; i < 2; i++) {
synchronized (Main.class) { // lock up Th2
// print iterations
for (int j = 0; j < 10; j++) {
System.out.println(Thread.currentThread().getName() + " iter = " + (j + 1));
}
// wake up other boss thread and let it know inner-iteration finished
Main.class.notify();
// wait for other thread to run
try {
Main.class.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("end of Sub outer---------------------- " + (i + 1));
}
}
}
}
}
需要额外的帮助:有人会告诉我synchronized
是锁定共享资源的好方法还是其他更好的选择?说ReentrantLock
?另外,notify()
和wait()
是实现线程间通信的好方法,还是有更好的方法来使这种错误更容易发生并且效率更高?
答案 0 :(得分:0)
经过一番思考和努力,我提出了一个“实现”,可以“满足”我的期望,如问题帖中所述。我对wait
和notify
对进行了一些更改,并添加了一个isTh2RunFirst
标志来辅助两个线程的通信。这是代码:
public class InterThCom {
// flag default to false for checking if sub-thread
// gets the lock first
private boolean isTh2RunFirst = false;
public static void main(String[] args) {
InterThCom itc = new InterThCom();
Thread t1 = new Thread(itc.new Th1(), "Boss-thread-");
Thread t2 = new Thread(itc.new Th2(), "Sub-thread-");
t1.start();
t2.start();
}
private class Th1 implements Runnable {
@Override
public void run() {
for (int i = 0; i < 2; i++) {
synchronized (InterThCom.class) { // lock up inner-loop
// boss-thread gets the lock first
// wait for sub-thread and let it run;
// otherwise, skip this check
if (isTh2RunFirst == false) {
// wait for sub-thread, if boss-thread gets the lock first
try {
InterThCom.class.wait();
} catch (InterruptedException e1) {
e1.printStackTrace();
}
}
// print iteration 100 times
for (int j = 0; j < 100; j++) {
System.out.println(Thread.currentThread().getName() + " iter-" + (j + 1));
}
// done printing 100 times
// sub-thread should run already at this point
isTh2RunFirst = true;
// This print helps split boss-th and sub-th prints
System.out.println(Thread.currentThread().getName() + " outer-loop iter:" + (i + 1));
// wake up sub-thread
InterThCom.class.notify();
// wait for sub-thread
try {
InterThCom.class.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
private class Th2 implements Runnable {
@Override
public void run() {
for (int i = 0; i < 2; i++) {
synchronized (InterThCom.class) {
// print iteration 10 times
for (int j = 0; j < 10; j++) {
System.out.println(Thread.currentThread().getName() + " iter-" + (j + 1));
}
// done printing 10 times
// sub-thread already prints j iteration
isTh2RunFirst = true;
// This print helps split boss-th and sub-th prints
System.out.println(Thread.currentThread().getName() + " outer-loop iter:" + (i + 1));
// wake up boss-thread
InterThCom.class.notify();
// wait for boss-thread
try {
InterThCom.class.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
synchronized (InterThCom.class) {
// boss-thread is waiting at the last iteration, so wake it up
InterThCom.class.notify();
}
}
}
}
如果有人想针对这种特定情况或一般情况下的详细情况,在线程通信的“适当”实现(就行业实践和效率而言)方面进行解决,我还会发布Code Review post。