This article mainly studies the application sample code of Java concurrency condition blocking Condition, as follows.
Condition breaks down the Object monitor methods (wait, notify, and notifyAll) into completely different objects so that by combining these objects with any Lock implementation, each object provides multiple wait sets (wait-set). Among them, Lock replaces the use of synchronized methods and statements, and Condition replaces the use of Object monitor methods.
Since Condition can be used to replace wait, notify and other methods, we can compare the code of inter-thread communication written before and take a look at the original problem:
There are two threads. The child thread executes 10 times first, then the main thread executes 5 times, then switches to the child thread executes 10, and then the main thread executes 5 times... This round trip is 50 times.
I used wait and notify to implement it before, but now I use Condition to rewritten it, the code is as follows:
public class ConditionCommunication {public static void main(String[] args) {Business business = new Business();new Thread(new Runnable() {// Open a child thread @Override public void run() {for (int i = 1; i <= 50; i++) {bussiness.sub(i);}}}).start();// main method main thread for (int i = 1; i <= 50; i++) {bussiness.main(i);}}}} class Business {Lock lock = new ReentrantLock();Condition condition = lock.newCondition();//Condition is a private lock on top of the specific lock Boolean bShouldSub = true;public void sub(int i) {lock.lock();try {while (!bShouldSub) {try {condition.await();//Use condition to call the await method}catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}}for (int j = 1; j <= 10; j++) {System.out.println("sub thread sequence of " + j + ", loop of " + i);}bShouldSub = false;condition.signal();//Use condition to send a wakeup signal and wake up a certain one} finally {lock.unlock();}}public void main(int i) {lock.lock();try {while (bShouldSub) {try {condition.await();//Use condition to call the await method}catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}}for (int j = 1; j <= 10; j++) {System.out.println("main thread sequence of " + j + ", loop of " + i);}bShouldSub = true;condition.signal();//Use condition to send a wake-up signal, wake up a certain one} finally {lock.unlock();}}}From the code point of view, Condition is used together with Lock. Without Lock, Condition cannot be used, because Condition is created through Lock. This usage is very simple. As long as you master the use of synchronized, wait, and notify, you can fully master the use of Lock and Condition.
The above uses Lock and Condition instead of synchronized and Object monitor methods to realize communication between two threads. Now let’s write a slightly more advanced application: simulate the blocking queue of the buffer.
What is a buffer? For example, there are many people who want to send messages now. I am a transit station and I want to help others send messages. So now I need to do two things. One thing is to receive messages sent by the user and put them in the buffer in order. The other thing is to take out messages sent by the user in order from the buffer and send them out.
Now abstract this actual problem: a buffer is an array. We can write data into the array or take data out of the array. The two things I need to do are to start two threads, one to store data and the other to get data. But the problem is that if the buffer is full, it means that there are too many messages received, that is, the message sent is too fast, and another thread of my life is not enough to send it, resulting in the buffer being left out, so the thread of data storage must be blocked and let it wait; on the contrary, if I forward it too fast, and now all the contents of the buffer have been sent by me and no new messages have been sent by the user, then the thread of data acquisition must be blocked at this time.
OK, after analyzing the blocking queue of this buffer, let’s use Condition technology to implement it:
class Buffer {final Lock lock = new ReentrantLock();//Define a lock final Condition notFull = lock.newCondition();//Define Conditionfinal Condition notEmpty = lock.newCondition();//Define Conditionfinal Object[] items = new Object[10];//For the following simulation, set the size of the blocking queue to 10, do not set too large int putptr, takeptr, count;//Array subscripts are used to calibrate the position //Storage data into the queue public void put(Object x) throws InterruptedException {lock.lock();//Lock try {while (count == items.length) {System.out.println(Thread.currentThread().getName() + "Blocked, data cannot be stored for the time being!");notFull.await();//If the queue is full, then block the thread of data storage, waiting to be woken up}//If it is not full, store items[putptr] = x;if (++putptr == items.length) //This is the judgment that reaches the end of the array. If it is reached, go back to the beginning putptr = 0;++count;//Number of message System.out.println(Thread.currentThread().getName() + " Save the value: " + x);notEmpty.signal();//Okay, now there is data in the queue. Wake up the thread with empty queue and you can get the data} finally {lock.unlock();//Download the lock}}//Fetch data from the queue public Object take() throws InterruptedException {lock.lock();//Lock try {while (count == 0) {System.out.println(Thread.currentThread().getName() + "Blocked, data cannot be retrieved for the time being!");notEmpty.await();//If the queue is empty, then the thread blocks the data to retrieve the thread, waiting to be woken up}//If it is not empty, take Object x = items[takeptr];if (++takeptr == items.length) //Judge whether it reaches the end, if it arrives, go back to the beginning takeptr = 0;--count;//The number of messages System.out.println(Thread.currentThread().getName() + " Get out the value: " + x);notFull.signal();//Okay, now there is a location in the queue. Wake up the thread full of the queue and you can store data. Return x;} finally {lock.unlock();//Lock}}}This program is classic, I took it out of the official JDK documentation and added comments. There are two conditions defined in the program, which are used to execute the two threads, and wait and wake up respectively. The idea is clear and the program is also very robust. One question can be considered, why do you need to use two Codes? There must be a reason for this design. If you use a Condition, now assume that the queue is full, but there are 2 threads A and B who store data at the same time, then they all enter sleep. OK, now another thread takes away one and then wakes up one of the threads A, then A can save it. After saving, A wakes up another thread. If B is awakened, there will be a problem, because the queue is full at this time and B cannot store it. If B stores, it will overwrite the value that has not been retrieved. Because a Condition is used, both storage and withdrawal use this Condition to sleep and wake up, and it will be messed up. At this point, you can understand the use of this Condition. Now let’s test the effect of the blocking queue above:
public class BoundedBuffer {public static void main(String[] args) {Buffer buffer = new Buffer();for (int i = 0; i < 5; i ++) {//Open 5 threads to store data in the buffer new Thread(new Runnable() {@Override public void run() {try {buffer.put(new Random().nextint(1000));//Save data randomly}catch (InterruptedException e) {e.printStackTrace();}}}).start();}for (int i = 0; i < 10; i ++) {//Open 10 threads to get data from the buffer new Thread(new Runnable() {@Override public void run() {try {buffer.take();//Fetch data from the buffer}catch (InterruptedException e) {e.printStackTrace();}}}).start();}}}}I deliberately enabled only 5 threads to store data and 10 threads to fetch data, just to make it blocked from getting data, and see the results of the operation:
Thread-5 is blocked and data cannot be retrieved for the time being!
Thread-10 is blocked and data cannot be retrieved for the time being!
Thread-1 Saved value: 755
Thread-0 Saved value: 206
Thread-2 Saved value: 741
Thread-3 Saved value: 381
Thread-14 Removed value: 755
Thread-4 Saved Value: 783
Thread-6 Take out the value: 206
Thread-7 Removed value: 741
Thread-8 Removed value: 381
Thread-9 Take out the value: 783
Thread-5 is blocked and data cannot be retrieved for the time being!
Thread-11 is blocked and data cannot be retrieved for the time being!
Thread-12 is blocked and data cannot be retrieved for the time being!
Thread-10 is blocked and data cannot be retrieved for the time being!
Thread-13 is blocked and data cannot be retrieved for the time being!
From the results, we can see that threads 5 and 10 are executed first, and they find that there is no in the queue, so they are blocked and sleep there. They can only get it until a new value is stored in the queue. However, they are not lucky, and the stored data is taken first by other threads. Haha... they can run it a few more times. If you want to see the data stored is blocked, you can set the thread to fetch the data a little less, and I won't set it here.
It's still the same question as before. Now let three threads execute it. Let's take a look at the question:
There are three threads, child thread 1 executes 10 times first, child thread 2 executes 10 times, then main thread executes 5 times, then switch to child thread 1 executes 10 times, child thread 2 executes 10 times, main thread executes 5 times... This round trip is 50 times.
If you don't use Condition, it's really hard to do, but it's very convenient to do it with Condition. The principle is very simple. Define three Conditions. After child thread 1 executes, child thread 2 wakes up the main thread, and main thread wakes up the child thread 1. The wake-up mechanism is similar to the buffer above. Let’s take a look at the code below, it’s easy to understand.
public class ThreeConditionCommunication {public static void main(String[] args) {Business business = new Business();new Thread(new Runnable() {// Open a child thread @Override public void run() {for (int i = 1; i <= 50; i++) {bussiness.sub1(i);}}}).start();new Thread(new Runnable() {// Start another child thread @Override public void run() {for (int i = 1; i <= 50; i++) {bussiness.sub2(i);}}}).start();// main method main thread for (int i = 1; i <= 50; i++) {bussiness.main(i);}}static class Business {Lock lock = new ReentrantLock();Condition condition1 = lock.newCondition();//Condition is a condition2 = lock.newCondition();Condition conditionMain = lock.newCondition();private int bShouldSub = 0;public void sub1(int i) {lock.lock();try {while (bShouldSub != 0) {try {condition1.await();//Use condition to call the await method}catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}}for (int j = 1; j <= 10; j++) {System.out.println("sub1 thread sequence of " + j + ", loop of " + i);}bShouldSub = 1;condition2.signal();//Let thread 2 execute} finally {lock.unlock();}}public void sub2(int i) {lock.lock();try {while (bShouldSub != 1) {try {condition2.await();//Use condition to call the await method}catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}}for (int j = 1; j <= 10; j++) {System.out.println("sub2 thread sequence of " + j + ", loop of " + i);}bShouldSub = 2;conditionMain.signal();//Let the main thread execute} finally {lock.unlock();}}public void main(int i) {lock.lock();try {while (bShouldSub != 2) {try {conditionMain.await();//Use condition to call the await method}catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}}for (int j = 1; j <= 5; j++) {System.out.println("main thread sequence of " + j + ", loop of " + i);}bShouldSub = 0;condition1.signal();//Let thread 1 execute} finally {lock.unlock();}}}}The code seems a bit long, but it is an illusion and the logic is very simple. That's all for summarizing the Condition technology in threads.
The above is the entire content of this article about the application code example of Java concurrency condition blocking condition. I hope it will be helpful to everyone. Interested friends can continue to refer to other related topics on this site. If there are any shortcomings, please leave a message to point it out. Thank you friends for your support for this site!