可以使用两个 Condition 实例来做到这一点。
(阻塞队列)
class BoundedBuffer {
final Lock lock = new ReentrantLock();
final Condition notFull = lock.newCondition();
final Condition notEmpty = lock.newCondition();
final Object[] items = new Object[100];
int putptr, takeptr, count;
public void put(Object x) throws InterruptedException {
lock.lock();
try {
while (count == items.length)
notFull.await();
items[putptr] = x;
if (++putptr == items.length) putptr = 0;
++count;
notEmpty.signal();
} finally {
lock.unlock();
}
}
public Object take() throws InterruptedException {
lock.lock();
try {
while (count == 0)
notEmpty.await();
Object x = items[takeptr];
if (++takeptr == items.length) takeptr = 0;
--count;
notFull.signal();
return x;
} finally {
lock.unlock();
}
}
}
【在实际当中 直接用ArrayBlockingQueue 类 就可以了,就不用在手动的写 上面的阻塞队列了】:如下:
E
- 在此 collection 中保持的元素类型
public interface BlockingQueue<E>
支持两个附加操作的 Queue
,这两个操作是:获取元素时等待队列变为非空,以及存储元素时等待空间变得可用。
BlockingQueue 方法以四种形式出现,对于不能立即满足但可能在将来某一时刻可以满足的操作,这四种形式的处理方式不同:第一种是抛出一个异常,第二种是返回一个特殊值(null 或false,具体取决于操作),第三种是在操作可以成功前,无限期地阻塞当前线程,第四种是在放弃前只在给定的最大时间限制内阻塞。下表中总结了这些方法:
抛出异常 | 特殊值 | 阻塞 | 超时 | |
插入 | add(e) |
offer(e) |
put(e) |
offer(e, time, unit) |
移除 | remove() |
poll() |
take() |
poll(time, unit) |
检查 | element() |
peek() |
不可用 | 不可用 |
BlockingQueue 不接受null 元素。试图 add、put 或 offer 一个 null 元素时,某些实现会抛出NullPointerException。null 被用作指示 poll 操作失败的警戒值。
【1】BlockingQueue 可以是限定容量的。它在任意给定时间都可以有一个 remainingCapacity,超出此容量,便无法无阻塞地 put 附加元素。没有任何内部容量约束的 BlockingQueue 总是报告Integer.MAX_VALUE 的剩余容量。
【2】BlockingQueue 实现主要用于生产者-使用者队列,但它另外还支持 Collection
接口。因此,举例来说,使用 remove(x) 从队列中移除任意一个元素是有可能的。然而,这种操作通常不 会有效执行,只能有计划地偶尔使用,比如在取消排队信息时。
【3】BlockingQueue 实现是线程安全的。所有排队方法都可以使用内部锁或其他形式的并发控制来自动达到它们的目的。然而,大量的 Collection 操作(addAll、containsAll、retainAll 和removeAll)没有 必要自动执行,除非在实现中特别说明。因此,举例来说,在只添加了 c 中的一些元素后,addAll(c) 有可能失败(抛出一个异常)。
【4】BlockingQueue 实质上不 支持使用任何一种“close”或“shutdown”操作来指示不再添加任何项。这种功能的需求和使用有依赖于实现的倾向。例如,一种常用的策略是:对于生产者,插入特殊的end-of-stream 或 poison 对象,并根据使用者获取这些对象的时间来对它们进行解释。
以下是基于典型的生产者-使用者场景的一个用例。注意,BlockingQueue 可以安全地与多个生产者和多个使用者一起使用。
class Producer implements Runnable { private final BlockingQueue queue; Producer(BlockingQueue q) { queue = q; } public void run() { try { while(true) { queue.put(produce()); } } catch (InterruptedException ex) { ... handle ...} } Object produce() { ... } } class Consumer implements Runnable { private final BlockingQueue queue; Consumer(BlockingQueue q) { queue = q; } public void run() { try { while(true) { consume(queue.take()); } } catch (InterruptedException ex) { ... handle ...} } void consume(Object x) { ... } } class Setup { void main() { BlockingQueue q = new SomeQueueImplementation(); Producer p = new Producer(q); Consumer c1 = new Consumer(q); Consumer c2 = new Consumer(q); new Thread(p).start(); new Thread(c1).start(); new Thread(c2).start(); } }
内存一致性效果:当存在其他并发 collection 时,将对象放入 BlockingQueue
之前的线程中的操作happen-before 随后通过另一线程从 BlockingQueue
中访问或移除该元素的操作。
此接口是 Java Collections Framework 的成员。
。。。。结束。
<<<<<--------
(ArrayBlockingQueue 类提供了这项功能,因此没有理由去实现这个示例类。) 可参见:JDK文档。
Condition 实现可以提供不同于 Object 监视器方法的行为和语义,比如受保证的通知排序,或者在执行通知时不需要保持一个锁。应用实例:
package com.itm.thread; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /********* * * 子线程循环10次,接着主线程循环100次,接着又回到子线程循环10次,接着再回到主线程循环100次,如此循环50次,请写出程序 * * * @author * */ public class ConditionCommunication { /** * @param args */ public static void main(String[] args) { final Business business = new Business(); new Thread(new Runnable() { @Override public void run() { for (int i = 1; i <= 50; i++) { business.sub(i); } } }).start(); // 主线程。 for (int i = 1; i <= 50; i++) { business.main(i); } } static class Business { Lock lock = new ReentrantLock(); Condition condition = lock.newCondition(); private boolean bShouldSub = true; public void sub(int i) { lock.lock(); try { while (!bShouldSub) { try { condition.await(); // int x = 3/1; // 这里必须写成一句话。。。 } catch (Exception e) { e.printStackTrace(); } } // 如果 变量就等于 不ShouldSub,则不等待 就直接来了。 for (int j = 1; j <= 10; j++) { System.out.println("sub thread sequece of " + j + ", loop of " + i); } bShouldSub = false; condition.signal(); // this.notify(); } finally { lock.unlock(); } } public void main(int i) { lock.lock(); try { while (bShouldSub) { try { condition.await(); // this.wait(); } catch (Exception e) { e.printStackTrace(); } } for (int j = 1; j <= 100; j++) { System.out.println("main thread sequece of " + j + ", loop of " + i); } bShouldSub = true; condition.signal(); // this.notify(); } finally { lock.unlock(); } } } }
新需求:第一个循环100次,第二个循环10,第三个循环20次。
package com.itm.thread; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /********* * * * * * @author * */ public class ThreeConditionCommunication { /** * @param args */ public static void main(String[] args) { final Business business = new Business(); new Thread(new Runnable() { @Override public void run() { for (int i = 1; i <= 50; i++) { business.sub2(i); } } }).start(); new Thread(new Runnable() { @Override public void run() { for (int i = 1; i <= 50; i++) { business.sub3(i); } } }).start(); // 主线程。 for (int i = 1; i <= 50; i++) { business.main(i); } } static class Business { Lock lock = new ReentrantLock(); Condition condition1 = lock.newCondition(); Condition condition2 = lock.newCondition(); Condition condition3 = lock.newCondition(); private int shouldSub = 1; public void sub2(int i) { lock.lock(); try { while (shouldSub != 2) { try { condition2.await(); // int x = 3/1; // 这里必须写成一句话。。。 } catch (Exception e) { e.printStackTrace(); } } for (int j = 1; j <= 10; j++) { System.out.println("sub2 thread sequece of " + j + ", loop of " + i); } shouldSub = 3; condition3.signal(); // this.notify(); } finally { lock.unlock(); } } public void sub3(int i) { lock.lock(); try { while (shouldSub != 3) { try { condition3.await(); // int x = 3/1; // 这里必须写成一句话。。。 } catch (Exception e) { e.printStackTrace(); } } for (int j = 1; j <= 20; j++) { System.out.println("sub3 thread sequece of " + j + ", loop of " + i); } shouldSub = 1; condition1.signal(); // this.notify(); } finally { lock.unlock(); } } public void main(int i) { lock.lock(); try { while (shouldSub != 1) { try { condition1.await(); // this.wait(); } catch (Exception e) { e.printStackTrace(); } } for (int j = 1; j <= 100; j++) { System.out.println("main thread sequece of " + j + ", loop of " + i); } shouldSub = 2; condition2.signal(); // this.notify(); } finally { lock.unlock(); } } } }