Understanding Four Kinds of Synchronization Tools in One Paper

CountDownLatch

Interpretation:

CountDownLatch is equivalent to a latch with N locks on it. Only when N unlocks all the locks will the door open. How do you understand it? Let me give you an example of a race. In a race, the referee must wait for all the players to be ready before he can develop the starting gun. The runner can start running. CountDownLatch has two main methods. One is that await() will lock the current thread, which is equivalent to the referee standing at the starting point waiting for the players to be ready. The other is countDown method for unlocking, which is equivalent to calling countDown method to tell the referee that he is ready after the players are ready. When everyone is ready, the referee develops the command gun.

Code:

public class TestCountDownLatch {
    public static void main(String[] args) {
        // You need to wait for two threads, so the input parameter is 2
        CountDownLatch latch = new CountDownLatch(2);
        // This thread runs for 1 second
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("1 Number one is ready! It takes 1 second!");
                latch.countDown();
            }
        }).start();
        
        // This thread runs for 3 seconds
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("2 Number one is ready! It takes 3 seconds!");
                latch.countDown();
            }
        }).start();
        
        try {
            System.out.println("Please contestant number 1 and player 2!");
            // The main thread waits for two threads to finish executing and then continues executing.
            latch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        // After two threads are executed, the main thread resumes running
        System.out.println("The referee fired the gun. Players No. 1 and No. 2 ran!");
    }
}

Operation results:

Please contestant number 1 and player 2!
Player No. 1 is ready! It takes 1 second!
Player 2 is ready! It takes 3 seconds!
The referee fired the gun. Players No. 1 and No. 2 ran!

What if CountDownLatch was removed? The results will be as follows:

Please contestant number 1 and player 2!
The referee fired the gun. Players No. 1 and No. 2 ran!
Player No. 1 is ready! It takes 1 second!
Player 2 is ready! It takes 3 seconds!

The referee will develop the starting gun when the player is not ready, which is a mess.
In fact, one of the simplest uses of CountDownLatch is to calculate the time when the multithreaded execution is completed. As in the previous example, it took three seconds for two threads to execute in parallel.

CyclicBarrier

Interpretation:

Cyclic Barrier acts like a fence, blocking threads. Cyclic is circular, indicating that the tool can be recycled. The construction parameters of Cyclic Barrier (N) indicate that there are several threads that need to wait for each other. It is equivalent to N players agreed to race many times, each time the end of the race must wait for each other at the starting point. Readers may immediately wonder if this is not the same as Count Down Latch. Dissimilarity. Because CountDownLatch is the referee waiting for the player, the thread calling await() method, and the thread waiting for countDown() method. Cyclic Barrier is a contestant waiting for the contestant. It is the thread calling await() method that waits for each other until the other threads are running well before starting the next run.

Let's take an example. Two players compete in three rounds.

Code:

public class TestCyclicBarrier {
    // Number of Rounds Run by No.1 Player
    public static int countA = 1;
    // Number of Rounds Running by No. 2 Player
    public static int countB = 1;
    public static void main(String[] args) {
        // Fill in 2 to represent two threads waiting for each other
        CyclicBarrier barrier = new CyclicBarrier(2);

        new Thread(new Runnable() {
            @Override
            public void run() {
                // Running three rounds altogether
                for (int i = 0; i < 3; i++) {
                    System.out.println("1 Number one runs! Current section" + countA++ + "Round the game!");
                    // No. 1 runs slowly, three seconds at a time.
                    try {
                        Thread.sleep(3000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    try {
                        System.out.println("1 Number two arrives at the finish line!");
                        // Call the wait method, where you wait for other players
                        barrier.await();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } catch (BrokenBarrierException e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();


        new Thread(new Runnable() {
            @Override
            public void run() {
                // Three rounds of waiting
                for (int i = 0; i < 3; i++) {
                    System.out.println("2 Number one runs! Current section" + countB++ + "Round the game!");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    try {
                        System.out.println("2 Number two arrives at the finish line!");
                        // Call the wait method, where you wait for other players
                        barrier.await();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } catch (BrokenBarrierException e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();
    }

}

Operation results:

Player No. 1 starts running! The current first round!
Player 2 starts running! The current first round!
Player 2 arrives at the finish line.
Player 1 arrives at the finish line.
Player No. 1 starts running! The current second round!
Player 2 starts running! The current second round!
Player 2 arrives at the finish line.
Player 1 arrives at the finish line.
Player No. 1 starts running! The current third round!
Player 2 starts running! The current third round!
Player 2 arrives at the finish line.
Player 1 arrives at the finish line.

In each round, No. 1 and No. 2 will return to the starting line and wait for each other to start the next round.
What if you don't add Cyclic Barrier?

Player No. 1 starts running! The current first round!
Player 2 starts running! The current first round!
Player 2 arrives at the finish line.
Player 2 starts running! The current second round!
Player 2 arrives at the finish line.
Player 2 starts running! The current third round!
Player 1 arrives at the finish line.
Player No. 1 starts running! The current second round!
Player 2 arrives at the finish line.
Player 1 arrives at the finish line.
Player No. 1 starts running! The current third round!
Player 1 arrives at the finish line.

At this point, the No. 2 runs straight through the three rounds, not waiting for the No. 1 runner.

Semaphore

Semaphore English literally means semaphore. Its working mechanism is that every thread must acquire semaphores if it wants to get the chance to run. acquire() method blocks the acquisition semaphore, release() releases the semaphore. For example, suppose we go sightseeing, but worrying about tourists will affect everyone's experience, so they can only sell two tickets per hour. In this way, we can control the number of visitors in the amusement park.

Code:

public class TestSemaphore {

    public static void main(String[] args) {

        Semaphore semaphore = new Semaphore(0);
        System.out.println("Customers are waiting at the ticket office.");
        new Thread(new Runnable() {
            @Override
            public void run() {
                for (; ; ) {
                    try {
                        Thread.sleep(500);
                        // Waiting for tickets
                        semaphore.acquire();
                        System.out.println("Customers get admission tickets!");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {

                for (int i = 0; i < 3; i++) {
                    try {
                        // Wait an hour for tickets to be issued
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                    // Two tickets issued at one time
                    System.out.println("Ticket office" + (i + 1) + "Two tickets sold in an hour!");
                    semaphore.release();
                    semaphore.release();
                }
            }
        }).start();

        System.out.println("Ticket office starts selling tickets!");
    }
}

Operation results:

Customers are waiting at the ticket office.
Ticket office starts selling tickets!
The ticket office sold two tickets in the first hour!
Customers get admission tickets!
Customers get admission tickets!
The ticket office sold two tickets in the second hour!
Customers get admission tickets!
Customers get admission tickets!
The ticket office sold two tickets in the third hour!
Customers get admission tickets!
Customers get admission tickets!

Exchanger

Interpretation:

Exchanger provides a synchronization point where two threads exchange data with each other. Exchanger is a bit like Cyclic Barrier with two threads. Threads are waiting for each other. The difference is that Exchanger has more exchange operations. For example, when playing online games, buyers and sellers have to go to the same place on the map and trade face-to-face, paying for equipment with one hand.

Code:

public class TestExchanger {
    public static void main(String[] args) {
        Exchanger<String> exchanger = new Exchanger<>();
        
        new Thread(new Runnable() {
            @Override
            public void run() {
                String weapon = "equipment";
                System.out.println("I'm a seller. I take it with me." + weapon + "Come!");
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("The seller arrives at the trading place on the map.");
                try {
                    System.out.println("I'm a seller. I changed it back." + exchanger.exchange(weapon));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                String money = "Ten thousand game coins";
                System.out.println("I'm a buyer. I take it with me." + money + "Over here.");
                try {
                    Thread.sleep(4000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("The buyer arrives at the trading place on the map.");
                try {
                    System.out.println("I'm a buyer. I changed it back." + exchanger.exchange(money));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }
        }).start();
    }

Operation results:

I'm a seller. I came with my equipment!
I'm a buyer. I came with ten thousand game coins.
Seller arrives at the trading place
 The buyer arrives at the trading place
 I'm a buyer. I've changed my equipment.
I'm a seller. I got 10,000 game coins back.

If there are any mistakes, please comment and correct them.

Turn to my personal blog vc2x.com

Keywords: Java

Added by tmh766 on Thu, 10 Oct 2019 08:06:27 +0300