使用Java中的两个线程打印奇数和偶数
在本文中,我们将介绍如何使用Java中的两个线程来打印奇数和偶数。这是一个经常问到的重要的Java多线程面试问题。
由于使用两个线程来交替打印奇数和偶数,因此该程序还显示了如何同步线程以及线程间通信的工作方式。
使用两个线程打印奇数和偶数
我们可以使用wait和notify方法编写一个Java程序来打印奇数和偶数。参见示例。
我们还可以使用Semaphore编写Java程序,Semaphore是java.util.concurrent包中的同步帮助。参见示例。
使用wait()和notify()方法
在Java程序中,有两个Runnable任务,一个用于打印偶数,另一个用于打印奇数。创建了两个线程来运行这些任务,并且使用等待通知来完成线程间通信。
还有一个带有方法printEven()和printOdd()的Printer类,该类的实例在线程之间共享。
class PrintEvenTask implements Runnable{
Printer printer;
int max;
PrintEvenTask(Printer printer, int max){
this.printer = printer;
this.max = max;
}
@Override
public void run() {
for(int i = 2; i <= max; i+=2){
printer.printEven(i);
}
}
}
class PrintOddTask implements Runnable{
Printer printer;
int max;
PrintOddTask(Printer printer, int max){
this.printer = printer;
this.max = max;
}
@Override
public void run() {
for(int i = 1; i <= max; i+=2){
printer.printOdd(i);
}
}
}
public class Printer {
boolean evenFlag = false;
//Prints even numbers
public void printEven(int num){
synchronized (this) {
while(!evenFlag){
try {
wait();
} catch (InterruptedException e) {
System.out.println("Thread Interrupted" + e.getMessage());
}
}
System.out.println(Thread.currentThread().getName() + " - " + num);
evenFlag = false;
// notify thread waiting for this object's lock
notify();
}
}
//Prints odd numbers
public void printOdd(int num){
synchronized (this) {
while(evenFlag){
try {
//make thread to wait
wait();
} catch (InterruptedException e) {
System.out.println("Thread Interrupted" + e.getMessage());
}
}
System.out.println(Thread.currentThread().getName() + " - " + num);
evenFlag = true;
// notify thread waiting for this object's lock
notify();
}
}
public static void main(String[] args) {
Printer printer = new Printer();
// creating two threads
Thread t1 = new Thread(new PrintOddTask(printer, 10), "Odd");
Thread t2 = new Thread(new PrintEvenTask(printer, 10), "Even");
t1.start();
t2.start();
}
}
输出:
Odd - 1 Even - 2 Odd - 3 Even - 4 Odd - 5 Even - 6 Odd - 7 Even - 8 Odd - 9 Even – 10
一旦线程启动并开始执行其Runnable任务的run()方法,就会调用printEven()和printOdd()方法。根据布尔标志,其中一个线程进入等待状态,其他线程输出数字,并使用notify()方法通知另一个线程。
使用信号量
Java提供的信号量实现是一个计数信号量,其中信号量通过许可进行初始化。关键部分只能在获得许可后才能执行,并且可以在执行后释放。线程被阻塞,直到获得许可为止。
为了使用两个线程打印奇数和偶数,使用了两个信号量,一个信号量初始化为一个许可,另一个信号量初始化为零。具有一个许可的信号量用于打印奇数,而另一个具有信号量的信号用于打印偶数,因为它最初具有零许可,可确保不首先打印偶数。
class PrintEvenTask implements Runnable{
Printer printer;
int max;
PrintEvenTask(Printer printer, int max){
this.printer = printer;
this.max = max;
}
@Override
public void run() {
for(int i = 2; i <= max; i+=2){
printer.printEven(i);
}
}
}
class PrintOddTask implements Runnable{
Printer printer;
int max;
PrintOddTask(Printer printer, int max){
this.printer = printer;
this.max = max;
}
@Override
public void run() {
for(int i = 1; i <= max; i+=2){
printer.printOdd(i);
}
}
}
public class Printer {
boolean evenFlag = false;
Semaphore semaphoreEven = new Semaphore(0);
Semaphore semaphoreOdd = new Semaphore(1);
//Prints even numbers
public void printEven(int num){
try {
semaphoreEven.acquire();
} catch (InterruptedException e) {
System.out.println("Thread Interrupted" + e.getMessage());
}
System.out. println(Thread.currentThread().getName() + " - " + num);
semaphoreOdd.release();
}
//Prints odd numbers
public void printOdd(int num){
try {
semaphoreOdd.acquire();
} catch (InterruptedException e) {
System.out.println("Thread Interrupted" + e.getMessage());
}
System.out. println(Thread.currentThread().getName() + " - " + num);
semaphoreEven.release();
}
public static void main(String[] args) {
Printer printer = new Printer();
// creating two threads
Thread t1 = new Thread(new PrintOddTask(printer, 10), "Odd");
Thread t2 = new Thread(new PrintEvenTask(printer, 10), "Even");
t1.start();
t2.start();
}
}
输出:
Odd - 1 Even - 2 Odd - 3 Even - 4 Odd - 5 Even - 6 Odd - 7 Even - 8 Odd - 9 Even - 10
一旦线程启动并执行其Runnable任务的run()方法,则调用printEven()和printOdd()方法。由于semaphoreOdd实例是使用一个许可初始化的,因此它可以获取并运行代码,因为semaphoreEven实例具有0许可,因此另一个线程被阻止。
当semaphoreEven.release();时从printOdd()方法调用该方法,该方法将semaphoreEven的允许增量为1,然后可以在printEven()方法中获取它。相同方式semaphoreOdd.release();在printEven()方法中调用方法,以释放已获取的semaphoreOdd实例的许可。

