`
xyheqhd888
  • 浏览: 403688 次
  • 性别: Icon_minigender_1
  • 来自: 秦皇岛
社区版块
存档分类
最新评论

wait()和notify()

阅读更多

1.  wait()、notify()、notifyAll()方法是由Object类提供的方法,且都被声明为final,所以无法重新定义它们。通过这3个方法您可以要求线程进入等待,或者是通知线程回到Runnable状态。

2.  必须在被同步化的方法或区块中调用wait()方法,当对象的wait()方法被调用时,当前的线程会被放入对象的等待集合(Wait Set)中,线程会解除对对象的锁定,其他的纯种可竞争执行被同步化区块。被放在等待集合中的线程将不参与线程的排队,wait()可以指定等待的时间,如果指定时间,则时间到之后线程会再度加入排队,如果指定时间为0或者不指定,则线程会持续等待,直到被中断,或是被告知参与排队。

3. 当对象的notify()被调用时,它会从当前对象的等待集中通知一个线程加入排队。被通知的线程是随机的,被通知的线程会与其他正在执行的线程共同竞争对对象的锁定。如果调用notifyAll(),则所有在等待集中的线程都会被通知加入排队,这些线程会与其他正在执行的线程共同竞争对对象的锁定。

4.当线程调用到对象的wait()方法时,表示它要先让出对象的被同步区使用权并等待通知,或是等待一段指定的时间,直到被通知或时间到时再与其他线程竞争。如果可以执行时应从等待点开始执行。

5.生产者消费者实例:生产者--店员--消费者。店员一次只能拥有固定数量的产品,若生产者生产了过多的产品,店员叫生产者等一下,如果店中有空位放产品了再通知生产者继续生产,如果店中没有产品了,店员会告诉消费者等一下,如果有产品了再通知消费者来取走产品。

package ysu.hxy;

/*
* 店员类
*
*/
public class Clerk
{
	//-1表示目前没有产品
	private int product = -1;

	//这个方法由生产者调用
	public synchronized void setProduct(int product)
	{
		if(this.product != -1)
		{
			try
			{
				//目前店员没有空间收产品,请稍候!
				wait();
			}
			catch(InterruptedException e)
			{
				e.printStackTrace();
			}
		}

		this.product = product;
        System.out.printf("生产者设定(%d)%n",this.product);

		//通知等待区中的一个消费者可以继续工作了
		notify();
	}

	//这个方法由消费者调用
	public synchronized int getProduct()
	{
		if(this.product == -1)
		{
			try
			{
				//缺货了,请稍候
				wait();
			}catch(InterruptedException e)
			{
				e.printStackTrace();
			}
		}

		int p = this.product;
        System.out.printf("消费者取走(%d)%n",this.product);
		this.product = -1;

		//通知等待区中的一个生产者可以继续工作了
		notify();

		return p;
	}
}

 

package ysu.hxy;

public class Producer implements Runnable
{
	private Clerk clerk;

	public Producer(Clerk clerk)
	{
		this.clerk = clerk;
	}

	public void run()
	{
		System.out.println("生产者开始生产整数......");

		//生产1到10的整数
		for(int product = 1;product <= 10;product++)
		{
           try
			{
			   //暂停随机时间
			   Thread.sleep((int)Math.random() * 3000);
			}
		   catch(InterruptedException e)
			{
			   e.printStackTrace();
			}

			//将产品交给店员
			clerk.setProduct(product);
		}
	}
}

 

package ysu.hxy;

public class Consumer implements Runnable
{
	private Clerk clerk;

    public Consumer(Clerk clerk)
	{
		this.clerk = clerk;
	}

	public void run()
	{
		System.out.println("消费者开始消耗整数......");

		//消耗10个整数
		for(int i=1;i<=10;i++)
		{
			try
			{
				//等待随机时间
				Thread.sleep((int)Math.random()*3000);
			}
			catch(InterruptedException e)
			{
				e.printStackTrace();
			}

			//从店员处取走整数
			clerk.getProduct();
		}
	}
}

 下面编写范例来测试生产者、消费者与店员的行为。

package ysu.hxy;

public class ProductTest
{
	public static void main(String[] args) 
	{
		Clerk clerk = new Clerk();

		//生产者线程
		Thread producerThread = new Thread(new Producer(clerk));

		//消费者线程
		Thread consumerThread = new Thread(new Consumer(clerk));

		producerThread.start();
		consumerThread.start();
	}
}

 执行结果如下:

                                D:\hxy>java ysu.hxy.ProductTest
                                生产者开始生产整数......
                                消费者开始消耗整数......
                                生产者设定(1)
                                消费者取走(1)
                                生产者设定(2)
                                消费者取走(2)
                                生产者设定(3)
                                消费者取走(3)
                                生产者设定(4)
                                消费者取走(4)
                                生产者设定(5)
                                消费者取走(5)
                                生产者设定(6)
                                消费者取走(6)
                                生产者设定(7)
                                消费者取走(7)
                                生产者设定(8)
                                消费者取走(8)
                                生产者设定(9)
                                消费者取走(9)
                                生产者设定(10)
                                消费者取走(10)

   生产者会生产10个整数,而消费者会消耗10个整数。由于店员处只能放置一个整数,所以只能每生产一个就消耗一个。

   如果一个线程进入对象的等待集中,可以中断它的等待,这时将会发生InterruptedException异常。可以使用线程对象的interrupt()方法来中断等待的动作。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics