volatile test with CountDownLatch 본문

Programming/Java

volatile test with CountDownLatch

halatha 2011. 4. 14. 05:16
import java.util.Random;
import java.util.concurrent.CountDownLatch;

class TestVolatile2
{
	public static void main(String[] args)
	{ 
		try {
			final int N = 128;
			final int M = 8 * 1024 * 1024;
			final int TN = 4;
			{
				final	CountDownLatch	cdl	=	new CountDownLatch(TN);
				final	BadAtomicLong	al	=	new BadAtomicLong();
				Thread	t1	=	new Thread(new Runnable() {
					@Override public void run() {
						try {
							for ( int i = 0; i < 2 * TN * M; ++i) {
								al.getAndSet(N);
							}
						} catch (Exception e) {}
					}
				});
				t1.start();

				for (int i = 0; i < 4; ++i) {
					Thread	ti	=	new Thread(new Runnable() {
						@Override public void run() {
							try {
								long readCount = 0;
								long badCount = 0;
								for ( int i = 0; i < M; ++i) {
									Thread.yield();
									int sum = al.getValue();
									++readCount;
									if (N < sum) { 
										++badCount;
									}
								}
								System.out.printf(
									"Bad long: Bad %d of %d, %f%%\n",
									badCount, readCount,
									100.0 * (double) badCount / readCount);
							} catch (Throwable t) {t.printStackTrace();}
							finally {
								cdl.countDown();
							}
						}
					});
					ti.start();
				}
				cdl.await();
			}
			{
				final CountDownLatch cdl = new CountDownLatch(TN);
				final	VolatileAtomicLong	al	=	new VolatileAtomicLong();
				Thread	t1	=	new Thread(new Runnable() {
					@Override public void run() {
						try {
							for ( int i = 0; i < 2 * TN * M; ++i) {
								al.getAndSet(N);
							}
						} catch (Exception e) {}
					}
				});
				t1.start();

				for (int i = 0; i < 4; ++i) {
					Thread	ti	=	new Thread(new Runnable() {
						@Override public void run() {
							try {
								long readCount = 0;
								long badCount = 0;
								for ( int i = 0; i < M; ++i) {
									Thread.yield();
									int sum = al.getValue();
									++readCount;
									if (N < sum) { 
										++badCount;
									}
								}
								System.out.printf(
									"Volatile long: Bad %d of %d, %f%%\n",
									badCount, readCount,
									100.0 * (double) badCount / readCount);
							} catch (Throwable t) {t.printStackTrace();}
							finally {
								cdl.countDown();
							}
						}
					});
					ti.start();
				}
				cdl.await();
			}
			{
				final CountDownLatch cdl = new CountDownLatch(TN);
				final	GoodAtomicLong	al	=	new GoodAtomicLong();
				Thread	t1	=	new Thread(new Runnable() {
					@Override public void run() {
						try {
							for ( int i = 0; i < 2 * TN * M; ++i) {
								al.getAndSet(N);
							}
						} catch (Exception e) {}
					}
				});
				t1.start();

				for (int i = 0; i < 4; ++i) {
					Thread	ti	=	new Thread(new Runnable() {
						@Override public void run() {
							try {
								long readCount = 0;
								long badCount = 0;
								for ( int i = 0; i < M; ++i) {
									Thread.yield();
									int sum = al.getValue();
									++readCount;
									if (N < sum) { 
										++badCount;
									}
								}
								System.out.printf(
									"Good long: Bad %d of %d, %f%%\n",
									badCount, readCount,
									100.0 * (double) badCount / readCount);
							} catch (Throwable t) {t.printStackTrace();}
							finally {
								cdl.countDown();
							}
						}
					});
					ti.start();
				}
				cdl.await();
			}
		}
		catch (Throwable t) { t.printStackTrace(); }
	}
}

class BadAtomicLong {
	Random r = new Random(128445);
	int	a, b, c, d, e, f, g, h;
	synchronized void getAndSet(int n) { 
		//	updates so that the sum is always <= n
		//	(=n after the atomic operation)
		a = b = c = d = e = f = g = h = 0;
		switch (r.nextInt(8)) {
			case 0: a = n; break;
			case 1: b = n; break;
			case 2: c = n; break;
			case 3: d = n; break;
			case 4: e = n; break;
			case 5: f = n; break;
			case 6: g = n; break;
			case 7: h = n; break;
		}
	}
	int getValue() { 
		return a + b + c + d + e + f + g + h;
	}
}
class VolatileAtomicLong {
	Random r = new Random(128445);
	volatile int	a, b, c, d, e, f, g, h;
	synchronized void getAndSet(int n) { 
		//	updates so that the sum is always <= n
		//	(=n after the atomic operation)
		a = b = c = d = e = f = g = h = 0;
		switch (r.nextInt(8)) {
			case 0: a = n; break;
			case 1: b = n; break;
			case 2: c = n; break;
			case 3: d = n; break;
			case 4: e = n; break;
			case 5: f = n; break;
			case 6: g = n; break;
			case 7: h = n; break;
		}
	}
	int getValue() { 
		return a + b + c + d + e + f + g + h;
	}
}
class GoodAtomicLong {
	Random r = new Random(128445);
	volatile int	a, b, c, d, e, f, g, h;
	synchronized void getAndSet(int n) { 
		//	updates so that the sum is always <= n
		//	(=n after the atomic operation)
		a = b = c = d = e = f = g = h = 0;
		switch (r.nextInt(8)) {
			case 0: a = n; break;
			case 1: b = n; break;
			case 2: c = n; break;
			case 3: d = n; break;
			case 4: e = n; break;
			case 5: f = n; break;
			case 6: g = n; break;
			case 7: h = n; break;
		}
	}
	synchronized int getValue() { 
		return a + b + c + d + e + f + g + h;
	}
}
Comments