preface
Welcome to our GitHub repository Star: github.com/bin39232820… The best time to plant a tree was ten years ago, followed by now. I know many people don’t play QQ anymore, but for a moment of nostalgia, welcome to join the six-vein Shenjian Java rookie learning group, group chat number: 549684836 encourage everyone to write blog on the road of technology
omg
I don’t know what to say. Keep working. This book is almost finished
- π₯ the most comprehensive series of Concurrent Java programming challenges ever
- π₯ is the most comprehensive Java concurrency series on the underlying implementation of Java concurrency
- π₯ The most complete series of Concurrent Java memory models ever
- π₯ Java Multithreading: The most complete Series of Concurrent Java applications ever (part 1)
- π₯ Java Multithreading: The most complete Java concurrency series ever (ii)
- π₯ The most comprehensive Java concurrent series on the use and implementation of locks in Java (1)
- π₯ The most comprehensive Java concurrent series on the use and implementation of locks in Java (ii)
- π₯ the most comprehensive series of Java concurrency containers and frameworks ever
- π₯ 13 atomic manipulation classes in Java, the most complete Java concurrent series ever
Introduction to the
Several very useful concurrency utility classes are provided in the JDK parallel distribution package.
- Utility classes that provide concurrent process control
- CountDownLatch
- CyclicBarrier
- Semaphore
- Provides utility classes for exchanging data between threads
- Exchanger
Waiting for CountDownLatch to complete with multiple threads
CountDownLatch allows one or more threads to wait for other threads to complete an operation.
If there is such a requirement: we need to parse the data of multiple sheets in an Excel, we can consider using multi-threading at this time. Each thread parses the data of one sheet. After all the sheets are parsed, the program needs to prompt the parsing to be completed. In this requirement, the simplest way to implement the main thread waiting for all threads to finish parsing the sheet is to use the join() method as follows:
public static class JoinCountDownLatchTest { public static void main(String[] args) throws InterruptedException { Thread parser1 = new Thread(newRunnable() {
@Override
public void run() {
System.out.println("parser1 finish"); }}); Thread parser2 = new Thread(newRunnable() {
@Override
public void run() {
System.out.println("parser2 finish"); }}); parser1.start(); parser2.start(); parser1.join(); parser2.join(); System.out.println("all parser finish"); }}Copy the code
Join is used to make the current executing thread wait for the join thread to finish executing. This is done by constantly checking to see if the join thread is alive, and if so, making the current thread wait forever. Where wait(0) means to wait forever
CountDownLatch, available in JDK 1.5, also provides join functionality, and more than joins, as shown in the following example:
public static class CountDownLatchTest {
static CountDownLatch c = new CountDownLatch(3);
public static void main(String[] args) throws InterruptedException {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(1 + "--" + System.currentTimeMillis());
c.countDown();
System.out.println(2 + "--" + System.currentTimeMillis());
c.countDown();
try {
Thread.sleep(1000);
System.out.println(4 + "--" + System.currentTimeMillis());
c.countDown();
Thread.sleep(1000);
System.out.println(5 + "--" + System.currentTimeMillis());
c.countDown();
System.out.println(6 + "--" + System.currentTimeMillis());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
c.await();
System.out.println("3" + "--"+ System.currentTimeMillis()); }}Copy the code
1 -- 1558966154351
2 -- 1558966154351
4 -- 1558966155352
3 -- 1558966155352
5 -- 1558966156353
6 -- 1558966156353
Copy the code
The CountDownLatch constructor takes an int as a counter, passing N if you want to wait for N points to complete. When we call the countDown method of CountDownLatch, N will be -1 and the await method of CountDownLatch will block the current thread until N becomes zero. Since the countDown method can be used anywhere, the number of points can be either N threads or N steps in a thread. When used on multiple threads, the reference to CountDownLatch is passed to the thread.
The counter must be greater than or equal to 0, except that 0 is zero and calling the await method does not block the current thread. It is not possible to reinitialize or change the CountDownLatch object’s internal counter value. One thread calls the countDown method happening-before and another thread calls the await method.
CyclicBarrier
CyclicBarrier literally means CyclicBarrier. What it does is allow a group of threads to block when they reach a barrier (also known as a synchronization point), and the barrier will not open until the last thread reaches the barrier, and all threads blocked by the barrier will continue to run.
The CyclicBarrier’s default constructor is CyclicBarrier(int parties), whose argument is the number of threads that the barrier intercepts, and each thread calls the await method to tell the CyclicBarrier that I have reached the barrier and the current thread is blocked.
public static class CyclicBarrierTest {
private static CyclicBarrier c = new CyclicBarrier(2);
public static void main(String[] args) {
System.out.println("1 -" + System.currentTimeMillis());
new Thread(new Runnable() {
@Override
public void run() {
try {
System.out.println("2 --" + System.currentTimeMillis());
Thread.sleep(1000);
System.out.println("3 -" + System.currentTimeMillis());
c.await();
System.out.println("4 -" + System.currentTimeMillis());
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
try {
System.out.println("5 -" + System.currentTimeMillis());
c.await();
System.out.println("6 -" + System.currentTimeMillis());
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("7 -"+ System.currentTimeMillis()); }}Copy the code
1 -- 1558969130471 5 -- 1558969130471 2 -- 1558969130471 3 -- 1558969131471 4 -- 1558969131471 6 -- 1558969131471 7 -- 1558969131471 1558969131471Copy the code
If you change new CyclicBarrier(2) to new CyclicBarrier(3), the main thread and child threads will wait forever because there is no third thread to execute the await method, that is, no third thread has reached the barrier, so neither of the two threads that reached the barrier before will continue to execute.
CyclicBarrier also provides a more advanced constructor CyclicBarrier(int parties, Runnable barrierAction) that takes precedence over barrierAction when a thread reaches a barrier, facilitating more complex business scenarios.
The following is an example:
public static class CyclicBarrierTest2 {
static CyclicBarrier c = new CyclicBarrier(2, new A());
public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
try {
c.await();
} catch (Exception e) {
}
System.out.println(1);
}
}).start();
try {
c.await();
} catch (Exception e) {
}
System.out.println(2);
}
static class A implements Runnable {
@Override
public void run() { System.out.println(3); }}}Copy the code
CyclicBarrier sets the number of intercepting threads to 2, so the main thread must wait until the first thread and thread A have finished executing, and then output 2.
1 2 3Copy the code
CyclicBarrier and CountDownLatch
CountDownLatch’s counter can only be used once, while CyclicBarrier’s counter can be reset using the reset() method. So CyclicBarrier can handle more complex business scenarios. For example, if a calculation error occurs, you can reset the counter and have the thread execute again.
Semaphore that controls the number of concurrent threads
Semaphore is used to control the number of threads accessing a particular resource at the same time. It coordinates threads to ensure proper use of common resources.
Semaphore is hard to understand literally, but can only be likened to a traffic light that controls the flow of traffic. Such as xx to limit the flow of the road, at the same time allow only has one hundred vehicles on the road to exercise, the other must be waiting at an intersection, so before the one hundred car would see a green light, you can into the road, at the back of the car to see the red light, not into the xx road, but if five of the top one hundred car has left the xx road, In this case, the car is the thread. If the car is on the road, the thread is executing. If the car is off the road, the thread is finished.
- Application scenarios
- Semaphore can be used for flow control, especially when common resources are limited, such as database connections. If there is a demand, want to read tens of thousands of file data, because is IO intensive tasks, we can start the dozens of thread concurrently, but if after read into memory, also need to be stored in the database, and database connections only 10, only 10 threads at the same time we must control access to the database connection save the data, Otherwise, an error will be reported and the database connection cannot be obtained. At this point, you can use Semaphore to do flow control as follows:
public static class SemaphoreTest {
private static final int THREAD_COUNT = 20;
private static ExecutorService threadPool = Executors.newFixedThreadPool(THREAD_COUNT);
private static Semaphore s = new Semaphore(5);
public static void main(String[] args) {
for (int i = 0; i < THREAD_COUNT; i++) {
threadPool.execute(new MyRunnable(i));
}
threadPool.shutdown();
}
private static class MyRunnable implements Runnable {
private int index;
MyRunnable(int index) {
this.index = index;
}
@Override
public void run() {
try {
s.acquire();
System.out.println("save data -- "+ index); s.release(); } catch (InterruptedException e) { e.printStackTrace(); }}}}Copy the code
save data -- 0
save data -- 4
save data -- 3
save data -- 1
save data -- 2
save data -- 6
save data -- 5
save data -- 7
save data -- 9
save data -- 10
save data -- 8
save data -- 11
save data -- 12
save data -- 13
save data -- 14
save data -- 15
save data -- 16
save data -- 17
save data -- 18
save data -- 19
Copy the code
In the code, although there are 20 threads executing, only 5 concurrent executions are allowed. Semaphore(int permits) accepts an integer indicating the number of permits available. Semaphore(5) indicates that 5 threads are allowed to obtain the license, i.e., the maximum number of concurrent requests is 5. Semaphore is also very simple to use. First the thread uses Semaphore’s acquire() method to acquire a license, and then calls Release () to return the license. You can also try to obtain a license using the tryAcquire() method.
Data exchange between threads
Sanoer is a tool class used for collaboration between threads. Used for data exchange between threads. It provides a synchronization point at which two threads can exchange data with each other. The two threads exchange data using the Exchange method. If the first thread executes the Exchange () method first, it will wait until the second thread executes the Exchange () method. When both threads reach the synchronization point, the two threads can exchange data, passing the data produced by each thread to the other.
The following is the application scenario of SANo11003.
Sano1100can be used in genetic algorithms. In the genetic algorithm, two people need to be selected as mating partners. At this time, the data of the two people will be exchanged and the crossover rule will be used to get two mating results.
public static class ExchangerTest {
private static final Exchanger<String> exgr = new Exchanger<String>();
private static ExecutorService threadPool = Executors.newFixedThreadPool(2);
public static void main(String[] args) {
threadPool.execute(new Runnable() {
@Override
public void run() {try {// A enter bank statement data String A ="Bank statement A"; exgr.exchange(A); } catch (InterruptedException e) { e.printStackTrace(); }}}); threadPool.execute(newRunnable() {
@Override
public void run() {try {// B enter bank statement data String B ="Bank statement B";
String A = exgr.exchange(B);
System.out.println("Are data A and B consistent?" + A.equals(B)
+ ", A typed:" + A + ", B input is:+ B); } catch (InterruptedException e) { e.printStackTrace(); }}}); threadPool.shutdown(); }}Copy the code
Are the data of A and B consistent?false, A input is: bank statement A, B input is: bank statement BCopy the code
If either thread does not execute the exchange() method, it will wait for a long time. To avoid waiting, you can use exchange(V x, long timeout, TimeUnit Unit) to set the maximum waiting time.
conclusion
This article introduces several concurrent utility classes provided in the JDK along with some application scenarios. Remember the purpose of this utility class and try them out once you have a corresponding business scenario.
- Waiting for CountDownLatch to complete with multiple threads
- CyclicBarrier
- Semaphore that controls the number of concurrent threads
- Data exchange between threads
At the end
Because a lot of things, all copy from the book, very boring, but at the same time reading a book, is one of the most detailed learning methods, we follow the book to see the blog, perhaps it will be better.
I have a goal to write two or three articles a week. I hope I can keep it up for a year. I hope you can give me more suggestions so that I can learn more and make progress together.
Daily for praise
Ok, everybody, that’s all for this article, you can see people here, they are real fans.
Creation is not easy, your support and recognition, is the biggest motivation for my creation, we will see in the next article
Six pulse excalibur | article “original” if there are any errors in this blog, please give criticisms, be obliged!