该练习题需要借助Java传统的线程通信的知识。
首先,我们创建了一个打印类Print,该类中分别实现了打印数字printNums()方法、以及打印字符printChars()方法。
class Print
{
private boolean flag=false;
public synchronized void writeNums()
{
try
{
for(int i=1;i<=26;)
{
//如果flag为true,说明数字已经打印了,打印数字线程阻塞
if(flag)
{
wait();
}
else
{
System.out.print(i*2-1);
System.out.print(i*2);
//将标识设为true,表明打印数字线程已执行
flag=true;
i++;
//唤醒其他线程
notifyAll();
}
}
}
catch (InterruptedException ex)
{
ex.printStackTrace();
}
}
public synchronized void writeChars()
{
try
{
for(int i='A';i<='Z';)
{
//如果flag为false,说明字符已经打印了,打印字符线程阻塞
if(!flag)
{
wait();
}
else
{
System.out.print((char)i);
//将标识设为true,表明打印字符线程已执行
flag=false;
i++;
//唤醒其他线程
notifyAll();
}
}
}
catch (InterruptedException ex)
{
ex.printStackTrace();
}
}
}
在该Print类中,我们通过用synchronized关键词修饰这两个方法来把这两个方法变成同步方法。由于同步方法的同步监视器为调用该方法的类实例,所以在这两个方法中可以直接使用wait()、notifyAll()方法来实现对程序的控制。方法中的flag作为一个标记,用来标记当前时候已打印数字。当程序进入printNums()方法后,如果flag为true,则表明当前已经打印数字,程序调用wait()方法阻塞;否则程序上下执行打印数字操作,当打印数字操作完成后,系统将flag设为true,然后调用notifyAll()来唤醒其他被阻塞的线程——如果系统中有打印数字线程,打印数字线程也会被唤醒,但该打印数字线程执行到该方法的wait()处时再次进入阻塞状态,只有执行打印字符方法printChars()的打印字符线程才可以向下执行。同理,打印字符线程的运行流程也是如此。
打印数字、打印字符操作都被Print类进行了封装,所以在打印数字以及打印字符线程中,只需要用Print对象调用对应的方法即可。打印数字线程如下:
class PrintNumsThread extends Thread
{
private Print p;
public PrintNumsThread(Print p)
{
this.p=p;
}
public void run()
{
p.writeNums();
}
}
打印字符线程如下:
class PrintCharsThread extends Thread
{
private Print p;
public PrintCharsThread(Print p)
{
this.p=p;
}
public void run()
{
p.writeChars();
}
}
最后,给出测试类:
public class PrintTest
{
public static void main(String[] args)
{
Print p=new Print();
new PrintNumsThread(p).start();
new PrintCharsThread(p).start();
}
}
下面展示一下我运行的结果吧!