A birdview of core java concurrency

core-java-concurrency

Concepts

Procting shared data

Synchronized

Every object instance has a monitor that can be locked by one thread at a time. The _synchronized _keyword can be specifid on a method or in block form to lock the monitor. Modifying a field while synchronized on an object guarantees that subsequent reads from any other thread synchronized on the same object will see the updated value. It is important to note that writes outside synchronization or synchronized on a different object than the read are not necessarily ever visible to other threads.

Lock

public class Counter {
    private final Lock lock = new ReentrantLock();
    private int value = 0;
    public int increment() {
        lock.lock();
        try {
            return ++value;
        } finally {
            lock.unlock();
        }
    }
}

ReadWriteLock

public class statistic {
    private final ReadWriteLock lock = new ReentrantReadWriteLock();
    private int value;
    public void increment() {
        lock.writeLock().lock();
        try {
            value++;
        } finally {
            lock.writeLock().unlock();
        }
    }
    public int current() {
        lock.readLock().lock();
        try {
            return value;
        } finally {
            lock.readLock().unlock();
        }
    }
}

volatile

public class Processor implments Runnable {
    private volatile boolean stop;
    public void stopProcessing() {
        stop = true;
    }
    public void run() {
        while(!stop) {
            //.. do processing
        }
    }
}

Atomic classes

public class Counter {
    private AtomicInteger value = new AtomicInteger();
    public int next() {
        return value.incrementAndGet();
    }
}

Atomic classes are provided for booleans, integers, longs and object references as well as arrays of integers, longs, and object references.

ThreadLocal

public class TransactionManager {
    private static final ThreadLocal<Transaction> currentTransaction = new ThreadLocal<Transaction>() {
        @Override
        protected Transaction initialValue() {
            return new NullTransactin();
        }
    }
    public Transaction currentTransaction() {
        Transaction current = currentTransaction.get();
        if(current.isNull()) {
            current = new TransactionImpl();
            currentTransaction.put(current);
        }
        return current;
    }
}

Concurrent collections

Concurrent lists and sets

Concurrent maps

Queue

Deques

Threads

Thread interference

  1.  some plain codes intend to handle interruption signal by using Thread.interrupted() to test interruption mark.

Uncaught exception handling

Thread t = new Thread(runnable);
t.setUncaughtExceptionHandler(new Therad.UncaughtExceptionHandler() {
    void uncaughtException(Thread t, Throwable e) {
        // get Logger and log uncaught exception
    }
});
t.start();

Deadlock

Thread coordination

wait / notify

public class Latch {
    private final Object lock = new Object();
    private volatile boolean flag = false;
    public void waitTillChange() {
        synchronized(lock) {
            while(! flag) {
                try {
                    lock.wait();
                } catch (InterruptedException e) {
                }
            }
        }
    }
    public void change(0 {
        synchronized(lock) {
            flag = true;
            lock.notifyAll();
        }
    }
}

Some important things to note about this code:

Condition

public class LatchCondition {
    private final Lock lock = new ReentrantLock();
    private final Condition condition = lock.newCondition();
    private volatile boolean flag = false;
    public void waitTillChange() {
        lock.lock();
        try {
            while(! flag) {
                condition.await();
            }
        } finally {
            lock.unlock();
        }
    }
    public void change() {
        lock.lock();
        try {
            flag = true;
            condition.signalAll();
        } finally {
            lock.unlock();
        }
    }
}

Coordination classes

And the code example:

final CyclicBarrier cb = new CyclicBarrier(N);
for (int i = 0; i < N; i++) {
    final int idx = i;
    new Thread(new Runnable() {
        public void run() {
            System.out.println("T" + idx + ": await");
            try {
                cb.await();
            } catch (InterruptedException ex) {
                System.out.println("T" + idx + ": interrupted");
                return;
            } catch (BrokenBarrierException ex) {
                System.out.println("T" + idx + ": broken");
                return;
            }
            System.out.println("T" + idx + ": continue");
        }
    }).start();
}

T0: await
T1: await
T2: await
T2: continue
T1: continue
T0: continue

Lines can “jump” a little bit because threads in these examples print out information to console concurrently. So you may have slightly different results. CountDownLatch The CountDownLatch is initialized with a count. Threads may call await() to wait for the count to reach 0. Other threads (or same) may call countDown() to reduce count. Not reusable once the count has reached 0. Used to trigger an unknown set of threads once some number of actions has occurred.

倒计时闩, 利用它可以实现类似计数器的功能。比如有一个任务A,它要等待其他4个任务执行完毕之后才能执行,此时就可以利用CountDownLatch来实现这种功能了

Works like a counter – allows one or more threads to wait on await() method for another N threads to callcountDown() method N times (total number of calls should be N).

“HelloWorld app” for CountdownLatch:

final CountDownLatch cdl = new CountDownLatch(N);
        new Thread(new Runnable() {
            public void run() {
                System.out.println("awaiting...");
                try {
                    cdl.await();
                } catch (InterruptedException ex) {
                    System.out.println("await has been iterrupted");
                    return;
                }
                System.out.println("ready");
            }
        }).start();

        for (int i = 0; i < N; i++) {
            final int idx = i;
            new Thread(new Runnable() {
                public void run() {
                    System.out.println("T" + idx + ":countDown");
                    cdl.countDown();
                    System.out.println("T" + idx + ":continue");
                }
            }).start();
        }

Console output: