/** * 基于信号量实现的有界缓存 */ public class BoundedBuffer<E> { private final Semaphore availableItems, availableSpaces; private final E[] items; private int putPosition = 0, takePosition = 0; public BoundedBuffer(int capacity){ availableItems = new Semaphore(0); availableSpaces = new Semaphore(capacity); items = (E[]) new Object[capacity]; } public boolean isEmpty(){ return availableItems.availablePermits() == 0; } public boolean isFull(){ return availableSpaces.availablePermits() == 0; } public void put(E x) throws InterruptedException{ availableSpaces.acquire(); doInsert(x); availableItems.release(); } public E take() throws InterruptedException{ availableItems.acquire(); E item = doExtract(); availableSpaces.release(); return item; } private synchronized void doInsert(E x) { int i = putPosition; items[i] = x; putPosition = (++i == items.length) ? 0 : i; } private synchronized E doExtract() { int i = takePosition; E x = items[i]; items[i] = null; // let gc working takePosition = (++i == items.length) ?0 : i; return x; } }
public class BoundedBufferTests { @Test public void testIsEmptyWhenConstructed(){ BoundedBuffer<String> bf = new BoundedBuffer<String>(10); assertTrue(bf.isEmpty()); } @Test public void testIsFullAfterPuts() throws InterruptedException{ BoundedBuffer<String> bf = new BoundedBuffer<String>(10); for (int i=0; i<10; i++){ bf.put("" + i); } assertTrue(bf.isFull()); assertTrue(bf.isEmpty()); } }
@Test public void testTaskBlocksWhenEmpty(){ final BoundedBuffer<Integer> bb = new BoundedBuffer<>(10); Thread taker = new Thread(){ @Override public void run() { try { int unused = bb.take(); fail(); //不应执行到这里 } catch (InterruptedException e) { } } }; try { taker.start(); Thread.sleep(1000); taker.interrupt(); taker.join(2000); //保证即使taker永久阻塞也能返回 assertFalse(taker.isAlive()); } catch (InterruptedException e) { fail(); } }
/** * 测试BoundedBuffer的生产者-消费者程序 */ public class PutTakeTest { private static final ExecutorService pool = Executors.newCachedThreadPool(); private final AtomicInteger putSum = new AtomicInteger(0); private final AtomicInteger takeSum = new AtomicInteger(0); private final CyclicBarrier barrier; private final BoundedBuffer<Integer> bb; private final int nTrials, nPairs; public PutTakeTest(int capacity, int npairs, int ntrials) { this.bb = new BoundedBuffer<Integer>(capacity); this.nTrials = ntrials; this.nPairs = npairs; this.barrier = new CyclicBarrier(npairs * 2 + 1); } void test(){ try { for (int i=0; i<nPairs; i++){ pool.execute(new Producer()); pool.execute(new Consumer()); } barrier.await(); // 等待所有的线程就绪 barrier.await(); // 等待所有的线程执行完成 } catch (Exception e) { throw new RuntimeException(e); } } class Producer implements Runnable{ @Override public void run() { try { int seed = hashCode() ^ (int) System.nanoTime(); int sum = 0; barrier.await(); //等待所有线程都准备好了,再执行 for (int i=nTrials; i>0; --i){ bb.put(seed); sum += seed; seed = xorShift(seed); } putSum.getAndAdd(sum); barrier.await(); } catch (Exception e) { throw new RuntimeException(e); } } } class Consumer implements Runnable{ @Override public void run() { try { barrier.await(); //等待所有线程都准备好了,再执行 int sum = 0; for (int i=nTrials; i>0; --i){ sum += bb.take(); } takeSum.getAndAdd(sum); barrier.await(); } catch (Exception e) { throw new RuntimeException(e); } } } .., }
void testLeak() throws InterruptedException{ BoundedBuffer<Big> bb = new BoundedBuffer<Big>(CAPACITY); // 生成堆快照 for (int i=0; i<CAPACITY; i++){ bb.put(new Big()); } for (int i=0; i<CAPACITY; i++){ bb.take(); //这里必须会通过doExtract(): items[i] = null;来释放资源 } // 生成堆快照, 应该和上一个快照内存容量基本相同 } class Big { double[] data = new double[100000]; }
public class TestingThreadFactory implements ThreadFactory { public final AtomicInteger numCreated = new AtomicInteger(); //记录创建的线程数 private final ThreadFactory factory = Executors.defaultThreadFactory(); @Override public Thread newThread(Runnable r) { numCreated.incrementAndGet(); return factory.newThread(r); } }
/** * 验证线程扩展能力 * @throws InterruptedException */ public void testPoolExpansion() throws InterruptedException{ int MAX_SIZE = 10; TestingThreadFactory threadFactory = new TestingThreadFactory(); ExecutorService exec = Executors.newFixedThreadPool(MAX_SIZE, threadFactory); for (int i=0; i<10*MAX_SIZE; i++){ exec.execute(new Runnable() { @Override public void run() { try { Thread.sleep(Long.MAX_VALUE); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } }); } for (int i=0; i<20 && threadFactory.numCreated.get() < MAX_SIZE; i++){ Thread.sleep(100); } assertEquals(threadFactory.numCreated.get(), MAX_SIZE); exec.shutdownNow(); }
public synchronized void transferCredits(Account from, Account to, int amount){ from.setBalance(from.getBalance() - amount); if (random.nextInt(1000) > THRESHOLD){ Thread.yield(); } to.setBalance(to.getBalance() + amount); }
1. 衡量典型测试用例中的端到端性能。
2. 根据经验值来调整各种不同的限值,如线程数量,缓存容量等。
this.timer = new BarrierTimer(); this.barrier = new CyclicBarrier(npairs * 2 + 1, timer); /** * 基于栅栏的定时器 */ public class BarrierTimer implements Runnable{ private boolean started; private long startTime, endTime; @Override public synchronized void run() { long t = System.nanoTime(); if (!started){ started = true; startTime = t; } else{ endTime = t; } } public synchronized long getTime(){ return endTime - startTime; } public synchronized void clear(){ started = false; } }其测试方法:
void test(){ try { timer.clear(); for (int i=0; i<nPairs; i++){ pool.execute(new Producer()); pool.execute(new Consumer()); } barrier.await(); // 等待所有的线程就绪 barrier.await(); // 等待所有的线程执行完成 long nsPerItem = timer.getTime(); System.out.println("cost time: " + nsPerItem); } catch (Exception e) { throw new RuntimeException(e); } }测试用例:
public static void main(String[] args) throws InterruptedException { int tpt = 100000; //每个线程测试次数 for (int cap = 1; cap <= tpt; cap*=10){ System.out.println("Capacity: " + cap); for (int pairs = 1; pairs <= 128; pairs *= 2){ TimedPutTakeTest t = new TimedPutTakeTest(cap, pairs, tpt); System.out.println("Pairs: " + pairs); t.test(); Thread.sleep(1000); t.test(); Thread.sleep(1000); } } }
1. 保证垃圾回收在执行测试程序期间不被执行,可通过-verbose:gc查看垃圾回收信息。
2. 保证垃圾回收在执行测试程序期间执行多次,可以充分反映出运行期间的内存分配和垃圾回收等开销。
不吝指正。