7.3 环境(Condition)

环境(Condition)因素对对象的等待和通知方法(waite(),notify()和notifyall()方法)作为不同的状态对象,给这些对象的多个等待集合的影响。这里我们用锁(Lock)取代同步(synchronize)方法和阻塞,环境(Condition)取代对象的等待(wait)和唤醒(notifycation)的方法。

       Note 环境(Condition)实例本质上是包含一个锁(lock)。为了包含一个环境(Condition)实例给一个锁实例,我们运用锁(Lock)的newCondition()方法。

环境(Condition)声明了下面的方法:

  •        void await(): 强迫请求的线程处于等待状态直到它需要签名或打断。
  •   boolean await(long time, TimeUnit unit): 强迫请求的线程处于等待状态直到它需要签名或打断,或直到指定等待的时间范围内。
  •   long awaitNanos(long nanosTimeout): 强迫请求的线程处于等待状态直到它需要签名或打断,或直到指定等待的时间范围内。
  •   void awaitUniterruptibly():强迫请求的线程处于等待状态直到它需要签名。
  •   boolean awaitUnit(Date deadline): 强迫请求的线程处于等待状态直到它需要签名或打断,或直到指定截止时间。
  •   void signal():唤醒一个等待的线程。
  •   void signalAll():唤醒所有等待的线程。

下面的例子使用环境(Condition)的方法实例生产者与消费者的应用。

package com.owen.thread.chapter7;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class PC
{

	public static void main(String[] args)
	{
		Shared s = new Shared();
		new Producer(s).start();
		new Consumer(s).start();
	}
}

class Shared
{
	private char c;
	private volatile boolean available;
	private final Lock lock;
	private final Condition condition;

	Shared()
	{
		available = false;
		lock = new ReentrantLock();
		condition = lock.newCondition();
	}

	Lock getLock()
	{
		return lock;
	}

	char getSharedChar()
	{
		lock.lock();
		try
		{
			while (!available)
				try
				{
					condition.await();
				}

				catch (InterruptedException ie)
				{
					ie.printStackTrace();
				}
			available = false;
			condition.signal();
		} finally
		{
			lock.unlock();
			return c;
		}
	}

	void setSharedChar(char c)
	{
		lock.lock();
		try
		{
			while (available)
				try
				{
					condition.await();
				} catch (InterruptedException ie)
				{
					ie.printStackTrace();
				}
			this.c = c;
			available = true;
			condition.signal();
		} finally
		{
			lock.unlock();
		}
	}
}

class Producer extends Thread
{
	private final Lock l;
	private final Shared s;

	Producer(Shared s)
	{
		this.s = s;
		l = s.getLock();
	}

	@Override
	public void run()
	{
		for (char ch = 'A'; ch <= 'Z'; ch++)
		{
			l.lock();
			s.setSharedChar(ch);
			System.out.println(ch + " produced by producer.");
			l.unlock();
		}
	}
}

class Consumer extends Thread
{
	private final Lock l;
	private final Shared s;

	Consumer(Shared s)
	{
		this.s = s;
		l = s.getLock();
	}

	@Override
	public void run()
	{
		char ch;
		do
		{
			l.lock();
			ch = s.getSharedChar();
			System.out.println(ch + " consumed by consumer.");
			l.unlock();
		} while (ch != 'Z');
	}

}

上面的代码PCmain()方法实例Shared、Producer和Consumer的类。而Shared是通过Producer和Consumer实例化的。

     Producer和Consumer的构造者是在主线中被调用的。因为Share的实例化需要在Producer和Consumer的线程中,这个实例必须出现这些有效的线程中(尤其这些线程运行在不同的核中)。通过声明s使最终完成任务。在这个域中我们声明了一个volatile的变量,为了确保s在被初始化后不会更改。

     观察Share的构造器,你会察觉到,它创建了一个锁为lock = new ReentrantLock(),和一个环境(Condition),通过锁来创建的condition = lock.newCondition()。这个锁通过getLock()的方法获取有效的producer和consumer.

    producer线程执行Share的void setSharedChar(char c)的方法去产生一个字符和写出一条信息。这个方法锁定先前那个锁对象,并且进入一个while的循环重复测试是否可用,如果生产的字母可用于消费那么就会返回true.

      当available为true时,生产者就会去执行环境(condition)的await()方法去等待available变为fale。当消费者需要消费字母时,消费者发出信号给环境(condition)去唤醒生产者。(我运用一个循环去替代if语句,因为虚假唤醒是可能的和available可能总是为true.)

     之后离开循环,生产者的线程会记录新的字母,availble为true表明一个字母可以给消费者,并且通知环境去唤醒一个等待的生产者。最后,释放锁和执行setShareChar()。

       Note 在Producer的run()方法中,我们锁住了setSharedChar()和System.out.println();在Consumer的run()方法中,我们锁了getSharedChar()和System.out.println()。生产信息之前需要消费信息;消费信息之前需要生产信息。

在消费者的行为线程和getSharedChar()方法,类似于我们仅仅描述的生产者和setSharedChar()的方法。

       Note 我并没有使用try/finally的语句去确保锁在生产和消费中无效,因为我们不希望在上下文中抛出异常。

执行上面的代码,你可能等到如下的结果:

A produced by producer.
A consumed by consumer.
B produced by producer.
B consumed by consumer.
C produced by producer.
C consumed by consumer.
D produced by producer.
D consumed by consumer.
••••



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值