Site Search:

AtomicAction1.java

<Back



import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.*;

/*
 * This program shows multi-threading only makes sense when the computation per thread is heavy.
 * Creating thread is not free, sometimes, multi-threaded program could be slower than single thread
 * */
public class AtomicAction1 {
    // large number to average out JVM activities such as garbage collection,
    // initialization, optimization
    private static final int TOTALRUN = 200;
    private static final int TOTALTHREAD = 400;
    private static final int COUNT_PER_TREAD = 100;
    private static long count = 0;
    private static long totalTime = 0;
    private static AtomicLong CNT = new AtomicLong(0);
    // ordered thread safe set
    private static Set<Long> bank = new ConcurrentSkipListSet<>();
    // JVM will optimize during first a few runs, don't include them in
    // statistics
    // running the test in IDE such as eclipse and console will have different results, because IDE have max memory limits
    private static final int DISCARDFIRSTFEW = 20;

    public static void main(String... args) throws InterruptedException {
        System.out.println("available core number: "
                + Runtime.getRuntime().availableProcessors());
        totalTime = 0;
        runTest("singleThread");
        totalTime = 0;
        runTest("multiThreadWithLock");
        totalTime = 0;
        runTest("multiThreadWithAtomic");
    }

    private static void runTest(String type) throws InterruptedException {
        for (int i = 0; i < TOTALRUN; i++) {
            init();
            test(type, i);
            
        }
        System.out.println(type + " average time per run: "
                + (double) totalTime / (double) (TOTALRUN - DISCARDFIRSTFEW)
                + " miliseconds.");
    }

    private static void test(String type, int i) throws InterruptedException {
        switch (type) {
        case "singleThread":
            long t = runSingleThread();
            if (i >= DISCARDFIRSTFEW) {
                totalTime += t;
            }
            break;
        case "multiThreadWithAtomic":
            t = runMultiThread(true);
            if (i >= DISCARDFIRSTFEW) {
                totalTime += t;
            }
            
            break;
        case "multiThreadWithLock":
            t = runMultiThread(false);
            if (i >= DISCARDFIRSTFEW) {
                totalTime += t;
            }
            break;
        default:
            System.out.println("Unknown type");
        }
    }

    private static void init() {
        count = 0;
        CNT.set(0);
        bank.clear();
    }

    private static long runSingleThread() {
        long start = System.currentTimeMillis();
        for (int i = 0; i < TOTALTHREAD * COUNT_PER_TREAD; i++) {
            bank.add(count++);
        }
        return System.currentTimeMillis() - start;
    }

    private static long runMultiThread(boolean atomic)
            throws InterruptedException {
        long start = System.currentTimeMillis();
        CountDownLatch latch = new CountDownLatch(TOTALTHREAD);
        for (long i = 0; i < TOTALTHREAD; i++) {
            Thread thread;
            if (atomic) {
                thread = new Thread(new AtomicRunnalbe(latch));
            } else {
                thread = new Thread(new SynchRunnable(latch));
            }
            thread.start();
        }
        latch.await();
        return System.currentTimeMillis() - start;
    }

    private static class AtomicRunnalbe implements Runnable {
        private CountDownLatch latch;

        public AtomicRunnalbe(CountDownLatch latch) {
            this.latch = latch;
        }

        @Override
        public void run() {
            for (int i = 0; i < COUNT_PER_TREAD; i++) {
                bank.add(CNT.getAndIncrement());
            }
            latch.countDown();
        }
    }

    private static class SynchRunnable implements Runnable {
        private CountDownLatch latch;

        public SynchRunnable(CountDownLatch latch) {
            this.latch = latch;
        }

        @Override
        public void run() {
            for (int i = 0; i < COUNT_PER_TREAD; i++) {
                synchronized (bank) {
                    bank.add(count++);
                }
            }
            latch.countDown();
        }
    }

}