用JAVA交替显示线程



我想交替显示这两个线程,如下所示:

  • 线程1
  • 线程0
  • 线程1
  • 线程0

这是我开始的基本代码,我尝试了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) {
}


}

} ```


我看到了两种解决方案:

  1. 忙等待

每个线程在打印前等待。当条件成立时释放。我对indexToPrint使用了AtomicInteger,使每个线程的值同步。

此解决方案适用于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。这个对象是静态的(每个线程都通用(,所以只有一个线程可以同时进入这个块。

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

所有等待的线程现在都处于唤醒状态,实际线程离开了块。因此,一个线程可以再次尝试打印。

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

while在这里非常重要。所有线程都是用notifyAll()唤醒的,所以在唤醒之后,它们应该再次测试自己。

你可以在这里找到一份好的文档。

该代码基于上一个代码。与CCD_ 11使用相同。

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

随机睡眠时间也会在主线程内造成意外结果。让主线程在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();
}
}

最新更新