Opening
I believe that little partners know more or less about these two words. They are common thread communication tools in concurrent programming. The two are very similar, but they are different, which leads to a lot of confusion among many small partners, including me: what is the difference between them, and what scenarios are they applicable to?
Now listen to me slowly. If you don't want to see the example or process, you can pull it to the bottom to see the summary
atresia
Count down latch is commonly known as counter. Official explanation:
/** * A synchronization aid that allows one or more threads to wait until * a set of operations being performed in other threads completes. */ A synchronization helper that allows one or more threads to wait until the completion of a set of operations performed in another thread.
In other words, there can be one or more threads, waiting for other threads to complete an operation before continuing.
What do you mean? Here's a chestnut:
In our life, we should often meet a situation. When we take a bus, especially at the departure station, the driver's master will wait until the number of passengers on the bus reaches a certain level in order to pull more passengers at a time. The test code is as follows:
public static void main(String[] args) { List<Passenger> list = new ArrayList<>(); Passenger p1 = new Passenger("Reading the meeting book"); Passenger p2 = new Passenger("Watch mobile phones"); Passenger p3 = new Passenger("See the scenery"); Passenger p4 = new Passenger("See the conductor"); list.add(p1); list.add(p2); list.add(p3); list.add(p4); ThreadPoolExecutor executor = new ThreadPoolExecutor(20, 200, 1000, TimeUnit.SECONDS, new LinkedBlockingQueue<>(3), new ThreadFactory() { private ThreadGroup group = (null == System.getSecurityManager() ? Thread.currentThread().getThreadGroup() : System.getSecurityManager().getThreadGroup()); private AtomicInteger num = new AtomicInteger(); @Override public Thread newThread(Runnable r) { Thread thread = new Thread(group, r,"zoo" + num.getAndIncrement(),0); thread.setDaemon(false); return thread; } }, new ThreadPoolExecutor.CallerRunsPolicy()); //Set latching release threshold CountDownLatch countDownLatch = new CountDownLatch(list.size()); log.error("The driver needs one car to start. Let's wait for someone..."); for (Passenger p : list) { executor.execute(()->gotoZOO(p,countDownLatch)); } try { countDownLatch.await(); log.error("Enough people, take off!"); executor.shutdown(); } catch (InterruptedException e) { e.printStackTrace(); } } private static void gotoZOO(Passenger p,CountDownLatch countDownLatch){ log.error("{}Our passengers are getting on",p.getDoWhat()); try { countDownLatch.countDown(); log.error("{}",p.doWhatOnBus()); } catch (Exception e) { e.printStackTrace(); } } static class Passenger{ private String doWhat; public Passenger(String doWhat) { this.doWhat = doWhat; } public String getDoWhat() { return doWhat; } public String doWhatOnBus() { return "It's so boring in the car,"+doWhat+"Come on!"; } }
results of enforcement
23:46:34.698 [main] ERROR com.test -The driver needs one car to start again. Let's wait 23:46:34.757 [zoo1] ERROR com.test -See the mobile phone passengers get on the bus 23:46:34.758 [zoo3] ERROR com.test -See the conductor get on the bus 23:46:34.757 [zoo0] ERROR com.test -The book reader got on the bus 23:46:34.759 [zoo1] ERROR com.test -It's so boring in the car. Look at your cell phone! 23:46:34.759 [zoo3] ERROR com.test -It's so boring in the car. Let's see the conductor! 23:46:34.757 [zoo2] ERROR com.test -The scenic passenger got on the bus 23:46:34.759 [zoo0] ERROR com.test -It's so boring in the car. Read books! 23:46:34.759 [zoo2] ERROR com.test -It's so boring in the car. Look at the scenery! 23:46:34.759 [main] ERROR com.test -Enough people, take off!
The driver (master thread) has to wait for 4 passengers before she starts to leave the car (waiting for the 4 sub threads to finish the countDown after calling it). And when passengers get on the train (calling countDown), they should do what they do and do their own things. They will not be foolish enough to stop doing anything because they get on the bus. (they will not block themselves by calling countDown). When the driver sees enough people (reaches the set threshold), he will start.
Locking summary:
After the main thread calls await, it will block waiting for other sub threads to call countDown method to reduce the threshold value to 0, and then continue to execute.
The child thread will not block because the countDown method is called
fence
Official explanation of the fence:
/** * A synchronization aid that allows a set of threads to all wait for * each other to reach a common barrier point. CyclicBarriers are * useful in programs involving a fixed sized party of threads that * must occasionally wait for each other. The barrier is called * <em>cyclic</em> because it can be re-used after the waiting threads * are released. */ Synchronization help allows a group of threads to wait for each other to reach a common barrier. CyclicBarriers are useful in programs involving a fixed size thread side, which sometimes have to wait for each other. The barrier is called < EM > cyclic < / EM > because it can be reused after releasing the waiting thread.
From the class annotation, we can roughly understand that it is used in a group, that is, multiple threads. When all threads reach a certain state, they block until all threads reach a certain state, and then continue to execute. And it can be reused.
The above description is still too obscure. Let's take a chestnut:
When we were children, our school organized spring outings, set the place, and when we arrived, we went in together. Write a simple example to see how the fence works in this scene
public static void main(String[] args) { List<Boy> list = new ArrayList<>(); Boy boy1 = new Boy("Look at the tiger"); Boy boy2 = new Boy("Watch orangutans"); Boy boy3 = new Boy("Watch the lion"); Boy boy4 = new Boy("See the conductor"); list.add(boy1); list.add(boy2); list.add(boy3); list.add(boy4); ThreadPoolExecutor executor = new ThreadPoolExecutor(20, 200, 1000, TimeUnit.SECONDS, new LinkedBlockingQueue<>(3), new ThreadFactory() { private ThreadGroup group = (null == System.getSecurityManager() ? Thread.currentThread().getThreadGroup() : System.getSecurityManager().getThreadGroup()); private AtomicInteger num = new AtomicInteger(); @Override public Thread newThread(Runnable r) { Thread thread = new Thread(group, r,"zoo" + num.getAndIncrement(),0); thread.setDaemon(false); return thread; } }, new ThreadPoolExecutor.CallerRunsPolicy()); //Initialize fence, set barrier threshold CyclicBarrier cyclicBarrier = new CyclicBarrier(list.size()); for (Boy boy : list) { executor.execute(()->gotoZOO(boy,cyclicBarrier)); } } private static void gotoZOO(Boy boy,CyclicBarrier cyclicBarrier){ log.error("We haven't arrived yet. Wait a minute,{}'s little boy starts to wait",boy.getWhere()); try { cyclicBarrier.await(); log.error("{}",boy.goWhere()); } catch (Exception e) { e.printStackTrace(); } } static class Boy{ private String where; public Boy(String where) { this.where = where; } public String getWhere() { return where; } public String goWhere() { return "We're all here. I'm going"+where+"la"; } }
Execution result:
22:05:59.476 [zoo2] ERROR com.test -People haven't arrived yet. Wait a minute. The little boy watching the lion begins to wait 22:05:59.477 [zoo1] ERROR com.test -People haven't arrived yet. Wait a minute. The little boy watching the orangutan begins to wait 22:05:59.477 [zoo0] ERROR com.test -People haven't arrived yet. Wait a minute. The little boy watching the tiger begins to wait 22:05:59.476 [zoo3] ERROR com.test -I haven't arrived yet. Wait a minute. The little boy of the conductor begins to wait 22:05:59.484 [zoo0] ERROR com.test -I'm going to see the tiger! 22:05:59.484 [zoo2] ERROR com.test -I'm going to see the lion! 22:05:59.484 [zoo3] ERROR com.test -I'm going to see the conductor! 22:05:59.484 [zoo1] ERROR com.test -I'm going to see the orangutans!
We can find that the first three little boys didn't enter the zoo after they arrived, but four little boys didn't enter the zoo until the fourth little boy arrived. Before that, one more little boy waited for each little boy (each thread called the await method), until all the people arrived (thread blocked waiting to reach the barrier point 4), each little boy The child goes back to the zoo to see the animals (each thread continues to perform its own task). It's like a fence at the gate of a zoo. It's a group ticket. You have to let children in every time when people arrive.
Fence summary
Each sub thread waits for each other until it reaches the threshold value of fence initialization
Differentiation and personal understanding
Blocking: it is similar to a statistical function (maybe this is why it is also commonly known as a counter). The main thread calls the await method to block and wait for the statistical results, while the sub thread is only responsible for calling the countDown method to tell the main thread that I am OK without blocking itself when the statistical requirements are met; there is a receiving result (main thread) and one or more sending quantity (sub thread) Process);
Fence: first, when a thread calls the await method, it will block the current thread. Second, I understand that it has no master child relationship like locking. It means that each thread waits for each other and continues to execute when it reaches a certain point.
Applicable scenarios
In fact, we can see from the above distinction: if it is necessary to summarize the interfaces whether the multithreaded execution is completed or not to a certain thread, and then continue the execution, for example, if each thread calculates an indicator, and then calculates the sum of all indicators or other indicators after the completion of calculation, then blocking can be used;
If only each thread needs to wait for each thread to finish, and then continue to do its own work, you can use fences. For example, three threads of ABC need to obtain 123 three indicators respectively, and then A needs to take the average of these three numbers, B needs to take the total, and C needs to take the variance. Then you need to wait for ABC to take 123 three indicators before you can calculate. At this time, fences can be used.
summary
Both of them are very good thread communication tools, but the details are different.
All in all:
Locking is to wait for the execution result of another thread in one thread;
And fences are threads waiting for each other, and then starting to do their own things at the same time
last
The code in this article is just for a better explanation of the difference between the two tools. If you don't write well, please forgive me a lot. If you find anything wrong, you are welcome to leave a message. Let's make progress together!