多线程通信其实就是多个线程在操作同一个资源.只是操作的动作不同,
例如下图的多个线程对同一资源的操作也一样,比如线程1和线程2都是写入操作;
线程3和线程4都是读取操作.
虽然写入操作的线程1,2和读取操作的线程3,4已经同步,但是仍然存在写入操作执行2次,读取操作执行一次或者写入操作执行一次,读取操作执行2次,
这根本的原因是因为写入操作或读取操作的线程之间没有进行通讯,没有达到写一次读一次的目的.
如果 写入操作和读取操作各自自有一个线程,那么操作便没问题,持同种操作的如果是多线程话,线程之间也要进行通信才行..
wait()、notify()和notifyAll()这三个函数由java.lang.Object类提供,用于协调多个线程对共享数据的存取。
下面是一个写入读取的例子:
class Res
{
private String name;
private String sex;
private boolean flag=false;
public void set(String name,String sex)
{
this.name=name;
this.sex=sex;
}
public void print()
{
System.out.println(name+"-----------"+sex);
}
public void setflag(boolean flag)
{
this.flag=flag;
}
public boolean getflag()
{
return flag;
}
}
class input implements Runnable
{
private Res r;
int x=0;
input(Res r)
{
this.r=r;
}
public void run()
{
while(x<100)
{
synchronized(r) //同步代码块
{
if(r.getflag()==true)
try
{
r.wait(); //判断如果已经写入,写入线程则wait();wait()同时throw一个InterruptedException异常,父类Runnable
} //不能处理该异常,不能throws只能内部trycatch处理.
catch (InterruptedException e)
{
}
if(x%2==0)
r.set("[Mike","male]");
else
r.set("[韩梅梅","性别女]");
x++;
r.setflag(true);
r.notifyAll(); //该出需要用notifyAll();否则4个线程都会陷入wait()状态.
System.out.print(Thread.currentThread().getName()+"|"+"input:"+x+"→");
}
}
}
}
class output implements Runnable
{
private Res r;
output(Res r)
{
this.r=r;
}
public void run()
{
int x=0;
while(x<100)
{
synchronized(r)
{
if(r.getflag()==false)
try
{
r.wait();
}
catch (InterruptedException e)
{
}
r.print();
r.setflag(false);
r.notifyAll();
x++;
System.out.println(Thread.currentThread().getName()+"|"+"output:"+x+"←┘");
}
}
}
}
class WaitNotifyDemo
{
public static void main(String[] args)
{
Res r=new Res();
input in=new input(r);
output ot=new output(r);
Thread t1=new Thread(in,"线程一");
Thread t2=new Thread(in,"线程二");
Thread t3=new Thread(ot,"线程三");
Thread t4=new Thread(ot,"线程四");
t1.start();
t2.start();
t3.start();
t4.start();
}
}
notifyAll()目的是为了唤醒对方操作的线程.但这里notifyAll()把己方线程一并唤醒,怎么才能做到只唤醒对方线程呢?
JDK 1.5中提供了多线程升级解决方案,他将同步synchronized替换成了显示的Lock操作,将Object类中的方法wait() notify() notifyAll()替换成了Condition类的对象,
该类对象可通过Lock锁进行获取:
import java.util.concurrent.locks.*; //需导入,
Lock lock=new Lock();
Condition cdt1=lock.newCondition();
Condition cdt2=lock.newCondition();
该锁绑定了2个Condition对象,一个锁可以绑定多个Condition对象.
Object方法 | Condition方法 |
wait() | await() |
notify() | signal() |
notifyAll() | signalAll() |
每个Condition对象的唤醒和等待是唯一识别的,即cdt1.await(),只能被cdt1.signal() ++| 或cdt1.signalAll()唤醒.|++此处不确定.
lock.lock()即便上锁,每次进入一个线程,直到该线程执行了lock.unlock();其他线程才可进入,
下面是一个面包房和学生的故事~~~
import java.util.concurrent.locks.*;
class resource
{
Lock lock=new ReentrantLock();
Condition con1=lock.newCondition();
Condition con2=lock.newCondition();
private String name;
private boolean flag=false;
private int num=1;
private final int maxnum=3000;
public void create(String name) throws InterruptedException
{
this.name=name;
while(num<maxnum)
{
lock.lock();
while(flag)
{
con1.await();
}
// try{wait();}catch(InterruptedException e){System.out.println("ssss");}
System.out.println(Thread.currentThread().getName()+"制造"+name+num);
flag=true;
con2.signal(); //生产线程生产一次,await(),唤醒消费线程,
// notifyAll();
lock.unlock();
}
}
public void consume() throws InterruptedException
{
while(num<=maxnum)
{
lock.lock();
while(!flag) //while使线程每次被唤醒都要判断flag
{
con2.await();
}
// try{wait();}catch(InterruptedException e){}
System.out.println(Thread.currentThread().getName()+"消费"+name+num);
flag=false;
num++;
con1.signal();
// notifyAll();
lock.unlock();
}
}
}
class creator implements Runnable
{
private resource r;
creator(resource r)
{
this.r=r;
}
public void run()
{
try
{
r.create("面包:");
}
catch (InterruptedException e)
{
}
}
}
class customer implements Runnable
{
private resource r;
customer(resource r)
{
this.r=r;
}
public void run()
{
try
{
r.consume();
}
catch (InterruptedException e)
{
}
}
}
class CreatorCustomerDemo
{
public static void main(String aaa[])
{
resource r=new resource();
creator fac=new creator(r);
customer cst=new customer(r);
Thread t1=new Thread(fac,"生产者线程:面包房");
Thread t2=new Thread(cst,"\t\t\t\t\t\t消费者线程:学生");
t1.start();
t2.start();
}
}