您的位置:首页 > 其它

多线程之间的通信

2017-04-25 22:52 120 查看

一,概述

1.什么时候需要线程间通信?

* 多个线程并发执行时, 在默认情况下CPU是随机切换线程的。

* 如果我们希望线程间有规律的切换, 就需要进行线程间通信。例如先让线程一执行,然后让线程一和线程二轮流交替执行。

2.怎么实现线程间通信?

实现线程间通信要借助于多线程同步,所以也分为两种方法,一种使用synchronized 关键字实现,另一种使用ReentrantLock 类实现。

二,使用synchronized 关键字实现线程间通信

重要点如下:

* 如果希望线程等待, 就调用wait()方法。

* 如果希望唤醒等待的线程, 就调用notify()方法。

* 这两个方法必须在同步代码中执行, 并且使用同步锁对象来调用。

代码示例如下:

首先声明两个成员方法:

int flag = 1;//定义一个标记
public void print01(){
synchronized (this){//this称为同步锁对象
if(flag != 1){
try {
this.wait();//调用wait方法,使线程处于等待状态。
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Log.d("kwwl","郭");
Log.d("kwwl","靖");
flag =2;
this.notify();//调用notify方法,唤醒线程
}
}
public void print02(){
synchronized (this){
if(flag == 1){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Log.d("kwwl","黄");
Log.d("kwwl","蓉");
flag =1;
this.notify();
}
}


同时开启两个线程,分别调用print01和print02方法,代码如下:

new Thread(new Runnable() {
public void run() {
while (true) {
print01();
}
}
}).start();

new Thread(new Runnable() {
public void run() {
while (true) {
print02();
}
}
}).start();


在上面print01和print02方法中都使用了synchronized 关键字构成了同步代码块,所以“郭”和“靖”一定同时打印,“黄”和“蓉”一定同时打印。但如果不使用wait方法和notify方法,则会出现“郭靖”打印了很多次才会打印“黄蓉”。而此时使用了wait方法和notify方法,实现了线程间通信功能,则“郭靖”和“黄蓉”轮流交替打印。

说明:this称为同步锁对象,他可以是任意类型的对象,但必须保证两个同步代码块的锁对象是同一个对象。

分析:

假设线程二先执行了,此时判断flag等于1,然后这个线程就会等待,此时线程1就会执行,但线程一执行后flag等于2,并调用notify来唤醒线程,这个方法是随机唤醒使用this锁等待的线程,此时只有线程二处于等待,所以线程二被唤醒。然后若还是线程一执行,那么因为此时flag等于2,所以线程一将被等待,所以就会执行线程二,等等依次执行。

注:如果是三个线程间的通信,可以使用this.notityAll方法,这个方法表示唤醒所有等待的线程。

三,使用ReentrantLock 类实现线程间通信

重要点如下:

*首先创建ReentrantLock 对象,然后再得到Condition 对象。

* 如果希望线程等待, 就调用await()方法。

* 如果希望唤醒等待的线程, 就调用signal()方法。

* 这两个方法必须在同步代码中执行, 并且使用同一个ReentrantLock 对象。

代码示例如下:

首先声明两个成员方法:

int flag = 1;
private ReentrantLock lock = new ReentrantLock();
Condition c1 = lock.newCondition();
Condition c2 = lock.newCondition();
public  void print01(){
lock.lock();
if(flag != 1){
try {
c1.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}

Log.d("kwwl","郭");
Log.d("kwwl","靖");
c2.signal();
lock.unlock();
}
public  void print02(){
lock.lock();
if(flag != 1){
try {
c2.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}

Log.d("kwwl","黄");
Log.d("kwwl","蓉");
c1.signal();//唤醒c1
lock.unlock();
}


再同时开启两个线程,分别调用两个方法,代码同上。

分析:首先使用ReentrantLock 对象的lock和unlock方法实现了同步代码块。然后又使用Condition类的await方法和signal方法实现了等待唤醒机制,实现了线程间通信。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息