线程间通信示例
多线程间通信:多个线程在处理同一资源,但是线程任务(执行代码)不同。如:
class Resource
{
String name;
String sex;
}
//输入
class Input implements Runnable
{
Resource r;
Input(Resource r)
{
this.r=r;
}
public void run()
{
int x=0;
int y=1;
while(y<=100)
{
synchronized(r)
{
if(x==0)
{
r.name=”mike”;
r.sex=”男”;
}
else
{
r.name="lili";
r.sex="女";
}
x=(x+1)%2;
}
}
}
}
//输出
class Output implements Runnable
{
Resource r;
Output(Resource r)
{
this.r=r;
}
public void run()
{
while(true)
{
synchronized(r)
{
//程序运行时需手动终止,以免输入线程完成了,输出线程还未执行完(可以两个线程共享一个计数器,使用计数器的两个线程使用同一个锁)
{
System.out.println(r.name+”…”+r.sex);
}
}
}
}
}
class ResourceDemo
{
//创建资源
Resource r=new Resource();
//创建任务
Input in=new Input(r);
Output out=new Output(r);
//创建线程,执行路径
Thread t1=new Thread(in);
Thread t2=new Thread(out);
//开启线程
t1.start();
t2.start();
}
上述程序,输入线程可能会连续多次输入,输入的数据还没被读取,就被覆盖了;同样,输出程序对同一数据连续多次输出。不合理!
需要完成这样的操作:输入线程输入新数据后,若输出程序还没有读取,则不能输入新的数据,直到输出线程读取数据才能再次输入;同样,输出线程输出数据后,没有新的数据,则不能再次输出,直到输入线程输入新数据才能再次读取。————等待/唤醒机制。
等待/唤醒机制:涉及的方法:wait()、notify()、notifyall()
1、 wait():让线程释放执行资格和执行权,使线程处于冻结状态,被wait的线程会被存储到线程池中,(对应锁的线程池)。
2、 notify():唤醒线程池中的一个线程(任意)
3、 notifyall():唤醒线程池中的所有线程。
这些方法都必须定义在同步中,因为这些方法是操作线程状态的方法,必须要明确到底操作的是哪个锁上的线程(必须是同一个锁)。
class Resource
{
String name;
String sex;
Boolean flag=false;
}
//输入
class Input implements Runnable
{
Resource r;
Input(Resource r)
{
this.r=r;
}
public void run()
{
int x=0;
int y=1;
while(y<=100)
{
synchronized(r)
{
if(r.flag)
{
try
{
r.wait();//使当前线程释放cpu的执行权和执行资格,在r锁的线程池中处于冻结状态
}
catch(InterruptedException e){ }
}
if(x==0)
{
r.name=”mike”;
r.sex=”男”;
}
else
{
r.name=”lili”;
r.sex=”女”;
}
r.flag=true;
x=(x+1)%2;
r.notify();//唤醒r锁的线程池中的任意一个处于冻结状态的线程;若输入线程没有释放执行权,继续执行到判断flag为true,wait释放执行权
}
}
}
}
//输出
class Output implements Runnable
{
Resource r;
Output(Resource r)
{
this.r=r;
}
public void run()
{
for(int x=1;x<=100;x++)
{
synchronized(r)
{
If(!r.flag)
{
try
{
r.wait();
}
catch(InterruptedException e){ }
}
{
System.out.println(r.name+”…”+r.sex);
r.flag=false;
r.notify();
}
}
}
}
}
class ResourceDemo
{
//创建资源
Resource r=new Resource();
//创建任务
Input in=new Input(r);
Output out=new Output(r);
//创建线程,执行路径
Thread t1=new Thread(in);
Thread t2=new Thread(out);
//开启线程
t1.start();
t2.start();
}
为什么操作线程的wait、notify、notifyall方法定义在Object类中?
答:这些方法是监视器的方法,监视器就是锁,锁可以是任意对象,任意对象都继承至Object方法,任意对象调用的方法一定定义在Object类中。
代码优化:
class Resource
{
private String name;
private String sex;
private Boolean flag=false;
public synchronized void set(String name, String sex)
{
if(this.flag)
{
try
{
this.wait();//使当前线程释放cpu的执行权和执行资格,在this锁的线程池中处于冻结状态
}
catch(InterruptedException e){ }
}
this.name=name;
this.sex=sex;
this.flag=true;
this.notify();
}
public synchronized void out()
{
if(this.flag)
{
try
{
this.wait();
}
catch(InterruptedException e){ }
}
System.out.println(name+”…”+sex);
flag=false;
this.notify();//唤醒this锁的线程池中的任意一个处于冻结状态的线程
}
}
//输入
class Input implements Runnable
{
Resource r;
Input(Resource r)
{
this.r=r;
}
public void run()
{
int x=0;
int y=1;
while(y<=100)
{
if(x==0)
{
r.set(“mike”,”男”);
}
else
{
r.set(“lili”,”女”);
}
x=(x+1)%2;
}
}
}
//输出
class Output implements Runnable
{
Resource r;
Output(Resource r)
{
this.r=r;
}
public void run()
{
for(int x=1;x<=100;x++)
{
r.out();
}
}
class ResourceDemo
{
//创建资源
Resource r=new Resource();
//创建任务
Input in=new Input(r);
Output out=new Output(r);
//创建线程,执行路径
Thread t1=new Thread(in);
Thread t2=new Thread(out);
//开启线程
t1.start();
t2.start();
}