Today, we will introduce several built-in java synchronizers.
CountDownLatch
CountDownLatch waits for a thread set until the count turns to 0. the Latch is one-time. Once the count is 0, it cannot be used any more.
Sample 1:
public class Driver { public static void main(String[] args) throws InterruptedException {CountDownLatch startSignal = new CountDownLatch(1);CountDownLatch doneSignal = new CountDownLatch(5);for (int i = 0; i < 5; ++i)// create and start threadsnew Thread(new Worker(startSignal, doneSignal)).start();doSomethingElse(); // don't let run yetstartSignal.countDown(); // startSignal change to zero, all threads begin to rundoneSignal.await(); // all thread await doneSignal to zeroSystem.out.println("All threads runs over");}private static void doSomethingElse() {System.out.println("don't let run yet");}}class Worker implements Runnable {private final CountDownLatch startSignal;private final CountDownLatch doneSignal;Worker(CountDownLatch startSignal, CountDownLatch doneSignal) {this.startSignal = startSignal;this.doneSignal = doneSignal;}public void run() {try {startSignal.await();System.out.println("Thread executing");doneSignal.countDown();} catch (InterruptedException ex) {} }}
Result:
Don't let run yet
Thread executing
Thread executing
Thread executing
Thread executing
Thread executing
All threads runs over
Sample 2
public class Driver2 { public static void main(String[] args) throws InterruptedException { CountDownLatch doneSignal = new CountDownLatch(3); Executor e = new ThreadPoolExecutor(3, 3, 10, TimeUnit.SECONDS, new ArrayBlockingQueue(5)); for (int i = 0; i < 3; ++i) // create and start threads e.execute(new WorkerRunnable(doneSignal, i)); doneSignal.await(); // wait for all to finish System.out.println("All threads are done"); } } class WorkerRunnable implements Runnable { private final CountDownLatch doneSignal; private final int i; WorkerRunnable(CountDownLatch doneSignal, int i) { this.doneSignal = doneSignal; this.i = i; } public void run() { doWork(i);doneSignal.countDown(); } void doWork(int i) { System.out.println("Thread " +i+" is working"); } }
Result:
Thread 0 is working
Thread 1 is working
Thread 2 is working
All threads are done
CyclicBarrier
Features are the same as CountDownLatch,CyclicBarrierIt can be used cyclically. You can call the reset () method to reset the barrier.
Sample:
public class Solver {final int N;final float[][] data;final CyclicBarrier barrier;class Worker implements Runnable {int myRow;Worker(int row) {myRow = row;}public void run() {while (!done()) {processRow();try {Thread.sleep((int)(Math.random() * 10)*1000);System.out.println(Thread.currentThread().getName() + " run over, and await");barrier.await();} catch (InterruptedException ex) {return;} catch (BrokenBarrierException ex) {return;}}}private void processRow() {for (int i = 0; i < data[0].length; i++) {data[myRow][i] = (float) Math.random() * 100;}}private boolean done() {if (data[myRow][data[0].length - 1] != 0) {return true;}return false;}}public Solver(float[][] matrix) {data = matrix;N = matrix.length;barrier = new CyclicBarrier(N+1, new Runnable() {public void run() {mergeRows();}private void mergeRows() {// TODO Auto-generated method stubSystem.out.println("row merge invoking");}});for (int i = 0; i < N; ++i)new Thread(new Worker(i)).start();waitUntilDone();}private void waitUntilDone() {try {barrier.await();System.out.println("all threads, done");} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (BrokenBarrierException e) {// TODO Auto-generated catch blocke.printStackTrace();}}public static void main(String[] args) {float[][] array = new float[6][6];Solver s = new Solver(array);}}
Result:
Thread-6 run over, and await
Thread-10 run over, and await
Thread-7 run over, and await
Thread-9 run over, and await
Thread-8 run over, and await
Thread-5 run over, and await
Row merge invoking
All threads, done
Exchanger (switch)
When two threads work in the same data cache area, they can use the switch (Exchanger). Typically, one thread fills in data into the buffer zone, and the other thread consumes the data. When both of them are completed, they exchange buffers.
SynchronousQueue (synchronous Queue)
Synchronous queue is a mechanism that pairs producers with consumer threads. When a thread calls the put Method of SynchronousQueue, it blocks until the other thread calls the take method, and vice versa. Unlike Exchanger, data is transmitted only in one direction and directed to the consumer.
Even if the SynchronousQueue class implements the BlockingQueue interface, it is not a queue in concept. It does not contain any elements, and its size method always returns 0.