Java 强制执行打印顺序,但线程在一次迭代后彼此等待

Java 强制执行打印顺序,但线程在一次迭代后彼此等待,java,multithreading,wait,notify,Java,Multithreading,Wait,Notify,我在解决这个问题时遇到了麻烦,因为我在等待另一个问题时遇到了问题(即使在查看了几个问题帖子之后)。下面是我试图做的:我想要一个线程(称为子线程)在外循环下打印10次,每次重复2次;然后另一个(boss线程)在外循环下打印100次,重复2次,前提是子线程先执行。它看起来像这样: Sub Thread- iter = 1 Sub Thread- iter = 2 ... Sub Thread- iter = 10 Boss Thread- iter = 1 Boss Thread- iter = 2

我在解决这个问题时遇到了麻烦,因为我在等待另一个问题时遇到了问题(即使在查看了几个问题帖子之后)。下面是我试图做的:我想要一个线程(称为子线程)在外循环下打印10次,每次重复2次;然后另一个(boss线程)在外循环下打印100次,重复2次,前提是子线程先执行。它看起来像这样:

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));
                }
            }
        }
    }
}
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();
            } 
        } 
    }

} 
公共类主{
公共静态void main(字符串[]args){
主ic=新主();
螺纹t1=新螺纹(ic.new Th1(),“凸台螺纹-”;
螺纹t2=新螺纹(ic.new Th2(),“子螺纹-”);
t2.start();
t1.start();
}
//凸台螺纹
私有类Th1实现Runnable{
@凌驾
公开募捐{
System.out.println(“TH1首先运行”);
synchronized(Main.class){//lock在外循环外所以
//boss线程可以选择下一个迭代
对于(int i=0;i<2;i++){
//等等,让子线程先运行
试一试{
Main.class.wait();
}捕捉(中断异常e){
e、 printStackTrace();
}
//打印迭代
对于(int j=0;j<100;j++){
System.out.println(Thread.currentThread().getName()+“iter=“+(j+1));
}
System.out.println(“外凸台末端------------------------------”+(i+1));
//唤醒子线程,让它知道内部迭代已完成
Main.class.notify();
}
}
}
}
//子线程
私有类Th2实现了Runnable{
@凌驾
public void run(){
对于(int i=0;i<2;i++){
已同步(Main.class){//锁定Th2
//打印迭代
对于(int j=0;j<10;j++){
System.out.println(Thread.currentThread().getName()+“iter=“+(j+1));
}
//唤醒另一个boss线程,让它知道内部迭代已完成
Main.class.notify();
//等待其他线程运行
试一试{
Main.class.wait();
}捕捉(中断异常e){
e、 printStackTrace();
}
System.out.println(“子外部结束------------------------------”+(i+1));
}
}
}
}
}

需要额外帮助:有人能告诉我
synchronized
是锁定共享资源的好方法还是有其他更好的替代方法?说
ReentrantLock
?另外,
notify()
wait()
是实现线程间通信的一种好方法,还是有更好的方法使这种通信更容易出错、更有效

经过思考和努力,我想出了一个“实现”方案,它“满足”了我在问题帖中所描述的期望。我对
wait
notify
对进行了一些更改,并添加了
isTh2RunFirst
标志,以帮助两个线程进行通信。代码如下:

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));
                }
            }
        }
    }
}
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();
            } 
        } 
    }

} 
公共类互联互通{
//标记默认值为false,用于检查是否存在子线程
//先得到锁
私有布尔值isTh2RunFirst=false;
公共静态void main(字符串[]args){
InterThCom itc=新的InterThCom();
螺纹t1=新螺纹(itc.new Th1(),“凸台螺纹-”);
线程t2=新线程(itc.new Th2(),“子线程-”);
t1.start();
t2.start();
}
私有类Th1实现Runnable{
@凌驾
public void run(){
对于(int i=0;i<2;i++){
已同步(InterThCom.class){//锁定内部循环
//boss线程首先获得锁
//等待子线程并让它运行;
//否则,跳过此检查
如果(isTh2RunFirst==false){
//等待子线程,如果boss线程首先获得锁
试一试{
InterThCom.class.wait();
}捕获(中断异常e1){
e1.printStackTrace();
}
} 
//打印迭代100次
对于(int j=0;j<100;j++){
System.out.println(Thread.currentThread().getName()+“iter-”+(j+1));
}
//打印100次
//此时子线程应该已经运行
isTh2RunFirst=true;
//此打印有助于分割凸台th和次th打印
System.out.println(Thread.currentThread().getName()+“外部循环iter:”+(i+1));
//唤醒子线程
InterThCom.class.notify();
//等待子线程
试一试{