您的位置:首页 > 大数据 > 人工智能

thread的wait\notify实现线程通信

2016-04-08 10:33 573 查看
背景:

之前的文章介绍过wait与sleep的区别,本文从另一个角度梳理一种实现线程通信的方式。

正文:

  wait()、notify()和notifyAll()是Object类中的方法:

  1)wait()、notify()和notifyAll()方法是本地方法,并且为final方法,无法被重写。

  2)调用某个对象的wait()方法能让当前线程阻塞,并且当前线程必须拥有此对象的monitor(即锁)

  3)调用某个对象的notify()方法能够唤醒一个正在等待这个对象的monitor的线程,如果有多个线程都在等待这个对象的monitor,则只能唤醒其中一个线程;

  4)调用notifyAll()方法能够唤醒所有正在等待这个对象的monitor的线程;
为何这三个不是Thread类声明中的方法,而是Object类中声明的方法(当然由于Thread类继承了Object类,所以Thread也可以调用者三个方法)?其实这个问题很简单,由于每个对象都拥有monitor(即锁),所以让当前线程等待某个对象的锁,当然应该通过这个对象来操作了。而不是用当前线程来操作,因为当前线程可能会等待多个线程的锁,如果通过线程来操作,就非常复杂了。

package thread;

public class NotifyTest {
public static Object object = new Object();
public static void main(String[] args) {
Thread1 thread1 = new Thread1();
Thread2 thread2 = new Thread2();
thread1.start();
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
thread2.start();
}

static class Thread1 extends Thread{
@Override
public void run() {
synchronized (object) {
try {
object.wait();
} catch (InterruptedException e) {
}
System.out.println("线程"+Thread.currentThread().getName()+"获取到了锁");
}
}
}

static class Thread2 extends Thread{
@Override
public void run() {
synchronized (object) {
object.notify();
System.out.println("线程"+Thread.currentThread().getName()+"调用了object.notify()");
<pre name="code" class="java"> <span style="white-space:pre">			</span>System.out.println("线程"+Thread.currentThread().getName()+"释放了锁");
} } }}

运行结果如下:



当然wait还有几个重载的方法设置超时时间:

public final void wait(long timeout) throws InterruptedException;

public final void wait(long timeout, int nanos) throws InterruptedException

导致线程进入等待状态直到它被通知或者经过指定的时间.

线面来看个常用的生产者消费者模式。模拟一个容器:

package thread;

import java.util.LinkedList;

public class Depository {
int capability = 5;
private static LinkedList<Product> pool = new LinkedList();
public LinkedList getPool() {
return pool;
}
public synchronized int getSize() {
return pool.size();
}
public synchronized boolean isEmpty() {
return pool.isEmpty();
}
public synchronized boolean isFull() {
if (this.getSize() == this.capability) {
return true;
} else {
return false;
}
}
public synchronized void addLast(Product p) {
this.notifyAll();
if (!this.isFull()) {
pool.addFirst(p);
//System.out.println("当前线程的名称:" + Thread.currentThread().getName());
System.out.println(Thread.currentThread().getName() + " 放入一个产品");
System.out.println("仓库已经有 " + this.getSize() + " 个了");

} else {
System.out.println("仓库满了,该线程" + Thread.currentThread().getName() + "等待");

try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}

public synchronized Product remove(){

if(!this.isEmpty()){//不为空,取出
this.notifyAll();  //
Product p=	pool.removeFirst();
return p;
}else{//等待
System.out.println("仓库空了,该线程" + Thread.currentThread().getName() + "等待");
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
}
}


package thread;

public class Product {

private String name;

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String toString(){
return "product:"+this.name;
}
}


package thread;
/**
*
* @author zhangliang
*
* 2016年4月8日 下午1:57:32
*/
public class PCTest {

public static void main(String[] args) throws InterruptedException {
// TODO Auto-generated method stub
PCTest test = new PCTest();
Depository pool = new Depository();
Producer pro=test.new Producer(pool);
Consumer con=test.new Consumer(pool);
Thread p =  new Thread(pro);
Thread c1 =  new Thread(con);
Thread c2 =  new Thread(con);
p.start();
c1.start();
c2.start();
Thread.sleep(500);
p.interrupt();
c1.interrupt();
c2.interrupt();

}

class Consumer implements Runnable{
//消费者线程拥有的资源
private Depository pool=null;
//构造函数
public Consumer(Depository pool)
{
this.pool=pool;
}
volatile boolean flag=true;
@Override
public void run() {
while(flag){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
flag =false;
}
Product p =	 this.pool.remove();
if(p!= null)
{
System.out.println("线程"+Thread.currentThread().getName()+"消费了"+p.toString());
}
}
}
}

//生产者线程
class Producer implements Runnable{
//生产者线程拥有的资源
private Depository pool=null;
//构造函数
public Producer(Depository pool)
{
this.pool=pool;
}

@Override
public void run() {
boolean flag=false;
while(true)
{
if(!pool.isFull())
{
Product p  = new Product();
p.setName("p:"+System.currentTimeMillis());
this.pool.addLast(p);
try {
Thread.sleep(10);
} catch (InterruptedException e) {
flag =false;
}
}
}
}
}

}


运行结果如下:

Thread-0 放入一个产品
仓库已经有 1 个了
Thread-0 放入一个产品
仓库已经有 2 个了
Thread-0 放入一个产品
仓库已经有 3 个了
Thread-0 放入一个产品
仓库已经有 4 个了
Thread-0 放入一个产品
仓库已经有 5 个了
线程Thread-2消费了product:p:1460095150363
Thread-0 放入一个产品
仓库已经有 4 个了
线程Thread-1消费了product:p:1460095150373
Thread-0 放入一个产品
仓库已经有 5 个了
Thread-0 放入一个产品
仓库已经有 5 个了
线程Thread-2消费了product:p:1460095150443
线程Thread-1消费了product:p:1460095150536
Thread-0 放入一个产品
仓库已经有 5 个了
线程Thread-2消费了product:p:1460095150546
Thread-0 放入一个产品
线程Thread-1消费了product:p:1460095150433
仓库已经有 4 个了
Thread-0 放入一个产品
仓库已经有 5 个了
线程Thread-1消费了product:p:1460095150646
Thread-0 放入一个产品
仓库已经有 5 个了
线程Thread-2消费了product:p:1460095150739
Thread-0 放入一个产品
仓库已经有 5 个了
线程Thread-2消费了product:p:1460095150749
线程Thread-1消费了product:p:1460095150636
Thread-0 放入一个产品
仓库已经有 4 个了
Thread-0 放入一个产品
仓库已经有 5 个了


1. 线程的等待或者唤醒,并不是让线程调用自己的wait或者notify方法,而是通过调用线程共享对象的wait或者notify方法来实现。

2. 线程要调用某个对象的wait或者notify方法,必须先取得该对象的监视器。

3. 线程的协作必须以线程的互斥为前提,这种协作实际上是一种互斥下的协作。

好了,本篇先到这里,下篇改用condition实现。

参考:
http://www.cnblogs.com/dolphin0520/p/3920385.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: