在BInderPool中有用到countdownLatch.整理如下:
简介
CountDownLatch是一个倒计数的同步锁存器。它和信号量有些差异。CountDownLatch是通过先调用await()阻塞当前进程,在其它线程中一直调用countdown()减小锁存器中的值count。当其它线程任务完成。count减至0.await()释放锁。而信号量则是信号量大于0时,可正常并发。而小于等于0时阻塞.CountDownLatch不支持重置count。如需重置count,可采用CyclicBarrier。
样例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| public class CountDownLatchDemo { private static final int PLAYER_AMOUNT = 5; public CountDownLatchDemo() { }
public static void main(String[] args) { CountDownLatch begin = new CountDownLatch(1); CountDownLatch end = new CountDownLatch(PLAYER_AMOUNT); Player[] plays = new Player[PLAYER_AMOUNT]; for(int i=0;i<PLAYER_AMOUNT;i++) plays[i] = new Player(i+1,begin,end); ExecutorService exe = Executors.newFixedThreadPool(PLAYER_AMOUNT); for(Player p:plays) exe.execute(p); System.out.println("Race begins!"); begin.countDown(); try{ end.await(); }catch (InterruptedException e) { e.printStackTrace(); }finally{ System.out.println("Race ends!"); } exe.shutdown(); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| public class Player implements Runnable {
private int id; private CountDownLatch begin; private CountDownLatch end; public Player(int i, CountDownLatch begin, CountDownLatch end) { super(); this.id = i; this.begin = begin; this.end = end; }
@Override public void run() { try{ begin.await(); Thread.sleep((long)(Math.random()*100)); System.out.println("Play"+id+" arrived."); }catch (InterruptedException e) { e.printStackTrace(); }finally{ end.countDown(); } } }
|
生产者消费者
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
| public class BlockingQueueTest { private static ArrayBlockingQueue<Integer> queue = new ArrayBlockingQueue<Integer>(5, true);
private static CountDownLatch producerLatch; private static CountDownLatch consumerLatch;
public static void main(String[] args) { BlockingQueueTest queueTest = new BlockingQueueTest(); queueTest.test(); }
private void test(){ producerLatch = new CountDownLatch(10); consumerLatch = new CountDownLatch(10);
Thread t1 = new Thread(new ProducerTask()); Thread t2 = new Thread(new ConsumerTask());
t1.start(); t2.start();
try { System.out.println("producer zero..."); producerLatch.await(); System.out.println("producer end"); } catch (InterruptedException e) { e.printStackTrace(); }
try { System.out.println("consumer waiting..."); consumerLatch.await(); System.out.println("consumer end"); } catch (InterruptedException e) { e.printStackTrace(); }
t1.interrupt(); t2.interrupt();
System.out.println("end"); }
class ProducerTask implements Runnable{ private Random rnd = new Random();
@Override public void run() { try { while(true){ queue.put(rnd.nextInt(100));
producerLatch.countDown(); } } catch (InterruptedException e) { } catch (Exception ex){ ex.printStackTrace(); } } }
class ConsumerTask implements Runnable{ @Override public void run() { try { while(true){ Integer value = queue.take();
System.out.println("value = " + value);
consumerLatch.countDown(); TimeUnit.SECONDS.sleep(2); } } catch (InterruptedException e) { } catch (Exception ex){ ex.printStackTrace(); } } }
}
|
ArrayBlockingQueue和LinkedBlockingQueue的区别:
队列中锁的实现不同
ArrayBlockingQueue实现的队列中的锁是没有分离的,即生产和消费用的是同一个锁;
LinkedBlockingQueue实现的队列中的锁是分离的,即生产用的是putLock,消费是takeLock
在生产或消费时操作不同
ArrayBlockingQueue实现的队列中在生产和消费的时候,是直接将枚举对象插入或移除的;
LinkedBlockingQueue实现的队列中在生产和消费的时候,需要把枚举对象转换为Node进行插入或移除,会影响性能
队列大小初始化方式不同
ArrayBlockingQueue实现的队列中必须指定队列的大小;
LinkedBlockingQueue实现的队列中可以不指定队列的大小,但是默认是Integer.MAX_VALUE