在 JAVA 中交替显示线程

Displaying threads alternatively in JAVA

我想像这样交替显示这两个线程:

这是我开始的基本代码,我尝试了 wait() notify() 方法,但我无法得到想要的结果。

class Task extends Thread {
    @Override
    public void run() {
        try {
            for(int i = 0; i<10; i++){

                double dure = Math.random()*200 ;
                sleep((long) dure);
                System.out.println(Thread.currentThread().getName());
            }
        } catch (Exception e) {
        }
    }
}

public class App {
    public static void main(String[] args) {

        Task t1 = new Task() ;
        Task t2 = new Task() ;

        t1.start();
        t2.start();


        try {
            t1.join();
            t2.join();
        } catch (InterruptedException e) {
        }
        
        
    }
    
} ```


 

随机休眠时间也会在 main 方法中导致意外结果,使主线程在 Thread1 和 Thread2 启动之间休眠可以帮助您了解谁是第一个启动打印任务的线程,之后你应该在任务中给予正确的休眠时间,让线程有可能交替打印。

class Task extends Thread {
@Override
public void run() {
    try {
        for(int i = 0; i<10; i++){
            sleep(2000);
            System.out.println(Thread.currentThread().getName());
        }
    } catch (Exception e) {
    }
}
}

public class App {
public static void main(String[] args) {

    Task t1 = new Task() ;
    Task t2 = new Task() ;

    t1.start();
   try {
    Thread.sleep(1000);
} catch (InterruptedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
}
    t2.start();

}
}

我看到两个解决方案:

  1. 忙等

每个线程在打印前等待。并在条件为真时释放。我将 AtomicInteger 用于 indexToPrint 以使每个线程的此值同步。

此解决方案适用于 n 个线程。

import java.util.concurrent.atomic.AtomicInteger;

class Task extends Thread {
    
    final static private AtomicInteger indexToPrint = new AtomicInteger(0);

    static private int threadNumber = 0;

    final private int index;

    /**
     *
     */
    public Task() {
        index = threadNumber++;
    }


    private int nextIndex() {
        return (index + 1) % threadNumber;
    }

    @Override
    public void run() {

        try {    

            for(int i = 0; i<10; i++){

                double dure = Math.random()*200 ;
                sleep((long) dure);

                while (indexToPrint.get() != index) {
                    sleep((long) 10);
                }
                indexToPrint.set(nextIndex());
                
                System.out.println(Thread.currentThread().getName());
                
            }
        } catch (Exception e) {}
    }
}
  1. 等待并通知

理解起来有点复杂,但没有无用的 CPU 使用。让我们解释一下同步块 synchronized (indexToPrint) {...} 是如何工作的。 该块同步监视静态对象 indexToPrint。这个对象是静态的(所有线程通用),所以只有一个线程可以同时进入这个块。

当一个线程进入块时,如果它的 indexindexToPrint 不同,则该线程将停止并 wait() 使另一个线程可以进入块。否则,打印线程名称,indexToPrint 更新为下一个线程索引,所有线程都被 notifyAll() 唤醒。最后,它离开了街区。

所有等待的线程现在都醒了,真正的线程离开了块。所以一个线程可以再次尝试打印。

重要的是要理解,当一个线程被置于等待状态然后发出通知时,它会准确地运行在它停止的地方。在这里,线程可以在两个位置停止:同步块之前和等待调用。

while在这里非常重要。所有线程都在 notifyAll() 醒来,所以在醒来后他们应该再次测试自己。

你可以找到一个好的documentation here

代码基于上一个。同样使用 indexToPrint.

import java.util.ArrayList;
import java.util.concurrent.atomic.AtomicInteger;

class Task extends Thread {

    static private final AtomicInteger indexToPrint = new AtomicInteger(0);

    static private int threadNumber = 0;

    final private int index;

    final private static ArrayList<Task> tasks = new ArrayList<>();

    /**
     *
     */
    public Task() {
        index = threadNumber++;
        tasks.add(this);
    }


    private int nextIndex() {
        return (index + 1) % threadNumber;
    }

    @Override
    public void run() {

        try {

            for(int i = 0; i<10; i++){

                double dure = Math.random()*200 ;
                sleep((long) dure);

                synchronized (indexToPrint) {
                    while (indexToPrint.get() != index) {
                        indexToPrint.wait();
                    }
                    indexToPrint.set(nextIndex());
                    System.out.println(Thread.currentThread().getName());
                    indexToPrint.notifyAll();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}