Java 之多线程通信(等待/唤醒)
多线程间通信: 多个线程在处理同一个资源, 但是任务却不同.
等待/唤醒机制
- 涉及的方法
wait()
: 让线程处于冻结状态, 被 wait() 的线程会被存储到线程池中notify()
: 唤醒线程池中的任意一个线程notifyAll()
: 唤醒线程池中所有的线程
- 这些方法必须定义在同步中, 因为这些方法是用于操作线程状态的方法, 必须要明确到底
操作的是哪个锁上的线程. - 为什么操作线程的方法 wait(), notify(), notifyAll() 定义在了 Object 类中?
因为这些方法是监视方法, 监视器其实就是锁. 而锁可以是任意的对象, 任意对象都能调用的方法一定
定义在 Object 类中.
// 资源
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;
while(true)
{
synchronized(r)
{
if(r.flag)
//该异常只能捕获, 不能抛出, 因为父类 Runnable 中 run() 方法没有异常
try{r.wait();}catch(InterruptedException e){}
if(x==0)
{
r.name = "mike";
r.sex = "nan";
}
else
{
r.name = "丽丽";
r.sex = "girlgirlgirl";
}
r.flag = true;
r.notify();
}
x = (x+1)%2; // 改变 x 的值, 获得不同的输入值
}
}
}
class Output implements Runnable
{
Resource r;
// 带参数的构造函数, 确保输入和输出线程操作的是同一个资源
Output(Resource r)
{
this.r = r;
}
public void run()
{
while(true)
{
synchronized(r) // 以资源对象作为锁, 输入线程和输出线程使用的为同一个锁
{
if(!r.flag)
try{r.wait();}catch(InterruptedException e){}
System.out.println(r.name + "......" + r.sex);
r.flag = flase;
r.notify();
}
}
}
}
class ResourceDemo
{
public static void main(String[] args)
{
// 创建资源
Resource r = new Resource();
// 创建任务
Input in = new Input(r); // 使用带参数的构造函数初始化, 确保操作的为同一个资源 r
Output out = new Output(r); //使用带参数的构造函数初始化, 确保操作的为同一个资源 r
// 创建线程
Thread t1 = new Thread(in);
Thread t2 = new Thread(out);
// 开启线程
t1.start();
t2.start();
}
}
<--------------------分隔线--------------------------------->
// 将属性私有化, 升级版
class Resource
{
private String name;
private String sex;
private boolean flag = false;
public synchronized void set(String name, String sex) //使用同步函数
{
if(flag)
try{this.wait();}catch(InterruptedException e){}
this.name = name;
this.sex = sex;
flag = true;
this.notify(); // 这时候的锁是 this
}
public synchronized void out()
{
if(!flag)
try{this.wait();}catch(InterruptedException e){}
System.out.println(name+"....."+sex);
flag = false;
this.notify();
}
}
class Input implements Runnable
{
Resource r;
Input(Resource r)
{
this.r = r;
}
public void run()
{
int x = 0;
while(true)
{
if(x==0)
{
r.set("mike","nan");
}
else
{
r.set("lili","nvnv");
}
x = (x+1)%2;
}
}
}
class Output implements Runnable
{
Resource r;
Output(Resource r)
{
this.r = r;
}
public void run()
{
while(true)
{
r.out();
}
}
}