我们首先用一个程序来解释多线程的通信。
在该程序中,Storage类中有存储和读取的方法,这样我们建立两个线程来分别利用Storage类中的两个方法,就能达到一个简单的通信.
package cn.itcast.example;
class Test{
public static void main(String[]args)
{
Storage st=new Storage();
Input input=new Input(st);//两个线程承接一个相同的类进而可以进行多线程的通信
Output output=new Output(st);
new Thread(input).start();
new Thread(output).start();
}
}
class Storage{ //建立一个用于多线程通信的类
private int[] cells=new int[10];
private int inPos,outPos;
public void put(int num)
{//建立写入数组元素的方法
if(inPos>=cells.length)inPos=0;
cells[inPos]=num;
System.out.println("在cells数组中["+inPos+"]位置放入元素:"+num);
inPos++;
}
public void get() {
if(outPos>=cells.length)outPos=0;
System.out.println("在cells数组中["+outPos+"]位置取出元素:"+cells[outPos]);
outPos++;
}
}
class Input implements Runnable{//建立一个多线程通信的一环,输入信息
private Storage st;
private int num;
Input(Storage st)
{
this.st=st;
}
public void run() {
while(true)
{
st.put(num++);
if(num==20)num=0;
}
}
}
class Output implements Runnable{
private Storage st;
Output(Storage st)
{
this.st=st;
}
public void run() {
while(true)
{
st.get();
}
}
}
运行结果:
我们能看出通过对数组的取用元素两个线程达到了通信。但我们还是能看到一个问题,在数组中放入元素中一定是按照我们既定的顺序的,但从数组中取出元素时,有时是没有按照我们的意愿的;通过分析我们可知,当放入元素的线程运行时(依据多线程运行机制)插入运行了取出元素的线程,但是当再次回到放入线程时,是不会影响到我们放入元素的位置和大小的。相反的,当取出元素线程中插入放入元素线程时,就有可能改变我们当前想要读取的数组,使得取出的元素不连续.
这里我们用同步锁来解决,这里在介绍三个方法
this.wait():使当前线程放弃同步锁并进入等待,直到其他线程进入该同步锁调用了this.notify()或this.notifyAll()方法
this.notify():唤醒此同步锁上等待的第一个调用this.wait()方法的线程
this.notifyAll():唤醒此同步锁上调用this.wait()方法的所有线程
这里我们利用上述方法来解决读取数据的不连续问题,我们来改写Storage类。
package cn.itcast.example;
class Test{
public static void main(String[]args)
{
Storage st=new Storage();
Input input=new Input(st);//两个线程承接一个相同的类进而可以进行多线程的通信
Output output=new Output(st);
new Thread(input).start();
new Thread(output).start();
}
}
class Input implements Runnable{//建立一个多线程通信的一环,输入信息
private Storage st;
private int num;
Input(Storage st)
{
this.st=st;
}
public void run() {
while(true)
{
st.put(num++);
if(num==20)num=0;
}
}
}
class Output implements Runnable{
private Storage st;
Output(Storage st)
{
this.st=st;
}
public void run() {
while(true)
{
st.get();
}
}
}
class Storage{
private int[] cells=new int[10];
private int count;
private int inPos,outPos;
public synchronized void put(int num)
{
try {
while(count==cells.length)
this.wait();//当写数据操作到达数组最大范围时,利用this.wait()方法,停止当前线程
cells[inPos]=num;
System.out.println("在cells["+inPos+"]中放入"+cells[inPos]);
if(++inPos==cells.length)
inPos=0;
count++;
this.notify();//这里来唤醒线程
}catch(Exception e)
{
}
}
public synchronized void get() {
try {
while(count==0)
this.wait();
System.out.println("在cells["+outPos+"]中取出"+cells[outPos]);
if(++outPos==cells.length)
outPos=0;
count--;
this.notify();
}catch(Exception e) {
}
}
}