Java并发工具包之印象篇二
转摘于http://www.importnew.com/26461.html
1、ConcurrentMap
java.util.concurrent.ConcurrentMap接口表示一个能够对别人的访问(插入和提取)进行并发出来的java.util.map。ConcurrentMap除了从父接口Map继承来的方法之外还有一些额外的原子性方法。
其接口的实现类:ConcurrentHashMap
ConcurrentHashMap和java.util.HashTable类很相似,但ConcurrentHashMap能够提供比HashTable更好的并发性能。在你从中读取对象的时候ConcurrentHashMap兵不会把整个Map锁住。
此外,在向其写入对象的时候,也不会锁住整个Map,其内部只是把Map中正在被写入的部分进行锁定。另外一个不同点事,在被遍历的时候,即使ConcurrentHashMap被改动,也不会抛出ConcurrentModificationException。尽管Iterator的设计不是为多个线程的同时使用。
ConcurrentMap concurrentMap = new ConcurrentHashMap();
concurrentMap.put("key", "value");
Object value = concurrentMap.get("key");
2、并发导航映射ConcurrentNavigableMap
它是一个支持并发访问的java.util.NavigableMap,它还能让它的子map具备并发访问的能力。所谓子map指的诸如headMap subMap tailMap之类的方法返回的map
headMap(T toKey) 方法返回一个包含了小于给定的toKey的key的子map。如果对原始map里的元素做了改动,这些改动将影响子map中的元素。
ConcurrentNavigableMap map = new ConcurrentSkipListMap();
map.put("1", "a");
map.put("2", "b");
map.put("3", "c");
ConcurrentNavigableMap headMap = map.HeadMap("2");
返回1,
ConcurrentNavigableMap headMap = map.tailMap("2");
返回2,3
ConcurrentNavigableMap headMap = map.subMap("2", "3");
返回2, 大于2小于3
=========================================================
2、闭锁CountDownLatch
它允许一个或多个线程等待一序列指定操作的完成。 CountDownLatch以一个给定的数量初始化,countDown每调用一次,数量就减一。通过调用await方法,线程可以阻塞等待这一数量达到令。
CountDownLatch latch = new CountDownLatch(3); Waiter waiter = new Waiter(latch); Decrementer decrementer = new Decrementer(latch); new Thread(waiter).start(); new Thread(decrementer).start(); Thread.sleep(4000); public class Waiter implements Runnable{ CountDownLatch latch = null; public Waiter(CountDownLatch latch) { this.latch = latch; } public void run() { try { latch.await(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Waiter Released"); } } public class Decrementer implements Runnable { CountDownLatch latch = null; public Decrementer(CountDownLatch latch) { this.latch = latch; } public void run() { try { Thread.sleep(1000); this.latch.countDown(); Thread.sleep(1000); this.latch.countDown(); Thread.sleep(1000); this.latch.countDown(); } catch (InterruptedException e) { e.printStackTrace(); } } }
3、栅栏CyclicBarrier
一个所有线程必须等待的一个栅栏,直到所有线程都到达这里,然后所有线程菜可以继续做其他事情。
Runnable barrier1Action = new Runnable() { public void run() { System.out.println("BarrierAction 1 executed "); } }; Runnable barrier2Action = new Runnable() { public void run() { System.out.println("BarrierAction 2 executed "); } }; CyclicBarrier barrier1 = new CyclicBarrier(2, barrier1Action); CyclicBarrier barrier2 = new CyclicBarrier(2, barrier2Action); CyclicBarrierRunnable barrierRunnable1 = new CyclicBarrierRunnable(barrier1, barrier2); CyclicBarrierRunnable barrierRunnable2 = new CyclicBarrierRunnable(barrier1, barrier2); new Thread(barrierRunnable1).start(); new Thread(barrierRunnable2).start();
CyclicBarrierRunnable 类
public class CyclicBarrierRunnable implements Runnable{ CyclicBarrier barrier1 = null; CyclicBarrier barrier2 = null; public CyclicBarrierRunnable( CyclicBarrier barrier1, CyclicBarrier barrier2) { this.barrier1 = barrier1; this.barrier2 = barrier2; } public void run() { try { Thread.sleep(1000); System.out.println(Thread.currentThread().getName() + " waiting at barrier 1"); this.barrier1.await(); Thread.sleep(1000); System.out.println(Thread.currentThread().getName() + " waiting at barrier 2"); this.barrier2.await(); System.out.println(Thread.currentThread().getName() + " done!"); } catch (InterruptedException e) { e.printStackTrace(); } catch (BrokenBarrierException e) { e.printStackTrace(); } } }
3、交换机Exchanger
两个线程可以进行互相交换对象的会和点。 两个线程通过一个Exchange交换对象。 交换对象的动作由exchange的两个exchange方法的其中一个完成
Exchanger exchanger = new Exchanger(); ExchangerRunnable exchangerRunnable1 = new ExchangerRunnable(exchanger, "A"); ExchangerRunnable exchangerRunnable2 = new ExchangerRunnable(exchanger, "B"); new Thread(exchangerRunnable1).start(); new Thread(exchangerRunnable2).start();
public class ExchangerRunnable implements Runnable{ Exchanger exchanger = null; Object object = null; public ExchangerRunnable(Exchanger exchanger, Object object) { this.exchanger = exchanger; this.object = object; } public void run() { try { Object previous = this.object; this.object = this.exchanger.exchange(this.object); System.out.println( Thread.currentThread().getName() + " exchanged " + previous + " for " + this.object ); } catch (InterruptedException e) { e.printStackTrace(); } } }
4、信号量semaphore
计数信号量。意味着它具备两个主要方法:acquire release。 每调用一次acquire,一个许可会被调用线程取走。每调用一次release,一个许可会被返给信号量。
信号量的主要两种用途
1、保护一个重要部分防止一次超过N个线程进入
Semaphore semaphore =
new
Semaphore(
1
);
//critical section
semaphore.acquire();
...
semaphore.release();
2、在两个线程之间发送信号
如果你将一个信号量用于两个线程之间传送信号,通常应该用一个线程调用acquire方法,另一个线程调用release方法。如果没有可用的许可,acquire调用将会阻塞,直到一个许可被另一个线程释放出来。如果无法往信号量释放更多许可时,一个release调用也会阻塞。
通过这个可以对多个线程进行协调。比如,如果线程A将一个对象插入到了一个共享列表list之后调用了acquire,而线程B则在从该列表中获取一个对象之前调用了release,这时已经创建了一个阻塞队列。 信号量中可用的许可的数量也就等同于该阻塞队列能够持有的元素个数。
无法担保第一个调用acquire的线程会是第一个获得一个许可的线程。如果第一个线程在等待一个许可时发生阻塞,而第二个线程前来索要一个许可的时候刚好有一个许可被释放出来,那么它就可能会在第一个线程之前获得许可。如果想要强制公平,Semaphore类由一个具有一个布尔类型的参数的构造方法,通过这个参数以告知Semaphore是否要强制公平。强制公平会影响到并发性能。
Semaphore sem = new Semphore(1, true);