Table of Contents
Management of state dependency
Home Java javaTutorial Implementation of blocking queue for actual state dependency management in JAVA development

Implementation of blocking queue for actual state dependency management in JAVA development

Jul 19, 2018 am 11:32 AM

The class library itself contains many classes with state dependencies. Such as FutureTask, BlockingQueue, etc. Some operations in these classes are based on state preconditions. For example, you cannot delete elements from an empty queue or obtain the calculation result of an unfinished task. Before executing these two operations, you must wait until the queue enters a non-empty state or the task enters the completed state. The simplest way for us to create state-dependent classes is to construct them based on a class library. But if the class library does not have the functionality you want, you can also use the underlying mechanism provided by the Java language and class library to construct your own synchronization mechanism.

So, this article will introduce how to construct your own state dependency class. Introduce step by step from the simplest construction to complex standardized construction, so as to understand the process and how to get the final result.

Management of state dependency

The blockable state dependency operation is shown in the following pseudo code:

acquire lock on object state //首先获取锁
     while (precondition does not hold) { //前提条件是否满足,不满足则一直循环重试
        release lock //释放锁
        wait until precondition might hold  //等待知道满足前提条件
        optionally fail if interrupted or timeout expire //中断或者超时,各种异常
        reacquire lock //重新获取锁
    }

perform action //执行任务
release lock  //释放锁
Copy after login

Acquire the lock, check whether the condition is met, and release it if not The lock enters the blocking state until the condition is met or interrupted, times out, etc., and the lock is reacquired. Execute the task and release the lock.

You may not be able to understand it intuitively when you look at this pseudocode now. It’s okay. Just read on and you will know what it means after reading this article. Every operation is constructed from this pseudocode architecture.

ArrayBlockingQueue is a bounded cache that provides two operations, put and take. They all contain a prerequisite: elements cannot be placed into a full cache, and elements cannot be retrieved from an empty cache. Well, our goal is to construct such an ArrayBlockingQueue.

Next, we will introduce two implementations of bounded cache, which use different methods to deal with situations where preconditions are not met.

First, let’s look at the following base class BaseBoundeBuffer. Subsequent implementations extend this base class. It is an array-based circular cache, and the variables buf, head, tail, and count contained are protected by the cache's built-in lock. It also provides synchronous doPut and doTake methods, and in subclasses, put and take operations are implemented through these methods, and the underlying state will be hidden from subclasses.

public abstract class BaseBoundedBuffer<V> {

    private final V[] buf;    
    private int tail;    
    private int head;    
    private int count;    
    protected BaseBoundedBuffer(int capacity) {        
    this.buf = (V[]) new Object[capacity];
        count = 0;
    }    
    protected synchronized final void doPut(V v) {
        buf[tail] = v;        if(++tail == buf.length)
            tail = 0;
        ++count;
    }    
    protected synchronized final V doTake() {
        V v = buf[head];
        buf[head] = null;        
        if(++head == buf.length)
        head = 0;
        --count;        
        return v;
    }    
    public synchronized final boolean isFull() {        
        return count == buf.length;
    }    
    public synchronized final boolean isEmpty() {        
        return count == 0;
    }
}
Copy after login

The first implementation of bounded cache synchronizes both put and take methods, checks first and then executes, and throws an exception if it fails.

public class GrumpyBoundedBuffer<V> extends BaseBoundedBuffer{

    protected GrumpyBoundedBuffer(int capacity) {        
        super(capacity);
    }    
    public synchronized void put(V v) throws BufferFullException {        
        if(isFull()) {            
            throw new BufferFullException();
       }
        doPut(v);
    }    
    public synchronized V take() throws BufferFullException {        
        if(isEmpty())            
            throw new BufferFullException();        
            return (V) doTake();
    }
}
Copy after login

As shown above, if the prerequisites are not met, an exception will be thrown directly. The so-called exception here refers to the cache being full or empty. In fact, this exception does not mean that the program is wrong. For example, seeing a red light does not mean that the signal light is abnormal, but waiting until the green light is crossing the road. So, what this means is that the caller is required to catch the exception and retry each cache operation.

Let’s look directly at the following client calling code:

private static GrumpyBoundedBuffer gbb = new GrumpyBoundedBuffer(5);
...while(true) {    try {
        V item = gbb.take();        
        break;
    } catch(BufferEmptyException e) {
        Thread.sleep(500);
    }
}
Copy after login

To put it bluntly, if the prerequisites are not met, try again until the conditions are met, so that it seems that blocking can be achieved Effect. But in this case, the caller must handle the failure of the precondition by himself, and the CPU is always occupied. The problem here is that it will be very troublesome for the caller to use this queue!

The second method, SleepyBoundedBuffer implements a simple blocking retry mechanism through polling and sleep, thus allowing the caller to strip off the retry mechanism and simplify the use of cache. Please look at the following code listing:

public class SleepyBoundedBuffer<V> extends BaseBoundedBuffer{

    protected SleepyBoundedBuffer(int capacity) {        
        super(capacity);        
        // TODO Auto-generated constructor stub
    }    
    public void put(V v) throws InterruptedException {        
        while(true) {            
            synchronized(this) {                
                if(!isFull()) {
                    doPut(v);                    
                    return;
                }
            }
            Thread.sleep(200);
        }
    }    
    public V take() throws InterruptedException{        
        while(true) {            
            synchronized(this) {                
            if(!isEmpty()) {                    
            return (V) doTake();
                }
            }
            Thread.sleep(200);
        }
    }
}
Copy after login

From the caller's perspective, this method works well. If an operation meets the prerequisites, it will be executed immediately, otherwise it will be blocked. The caller does not need to handle failures and retries, but the caller still needs to handle InterruptedException. Like most well-behaved blocking library methods, SleepyBoundedBuffer supports cancellation via interrupts.

The problem with SleepyBoundedBuffer is, how long is the sleep time setting reasonable? How can we achieve optimal performance? As shown in the figure below, the condition set by thread B is true, but A is still sleeping at this time. This sleep is the bottleneck of performance.

Well, is there some way to achieve it? When the condition is true, the thread wakes up immediately and executes it?
Let’s give it a try, I’ll explain it to you in the next article!

The above is the detailed content of Implementation of blocking queue for actual state dependency management in JAVA development. For more information, please follow other related articles on the PHP Chinese website!

Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

Video Face Swap

Video Face Swap

Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Tools

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment

Dreamweaver CS6

Dreamweaver CS6

Visual web development tools

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

Hot Topics

Java Tutorial
1655
14
PHP Tutorial
1252
29
C# Tutorial
1226
24
Is the company's security software causing the application to fail to run? How to troubleshoot and solve it? Is the company's security software causing the application to fail to run? How to troubleshoot and solve it? Apr 19, 2025 pm 04:51 PM

Troubleshooting and solutions to the company's security software that causes some applications to not function properly. Many companies will deploy security software in order to ensure internal network security. ...

How do I convert names to numbers to implement sorting and maintain consistency in groups? How do I convert names to numbers to implement sorting and maintain consistency in groups? Apr 19, 2025 pm 11:30 PM

Solutions to convert names to numbers to implement sorting In many application scenarios, users may need to sort in groups, especially in one...

How to elegantly obtain entity class variable names to build database query conditions? How to elegantly obtain entity class variable names to build database query conditions? Apr 19, 2025 pm 11:42 PM

When using MyBatis-Plus or other ORM frameworks for database operations, it is often necessary to construct query conditions based on the attribute name of the entity class. If you manually every time...

How to simplify field mapping issues in system docking using MapStruct? How to simplify field mapping issues in system docking using MapStruct? Apr 19, 2025 pm 06:21 PM

Field mapping processing in system docking often encounters a difficult problem when performing system docking: how to effectively map the interface fields of system A...

How does IntelliJ IDEA identify the port number of a Spring Boot project without outputting a log? How does IntelliJ IDEA identify the port number of a Spring Boot project without outputting a log? Apr 19, 2025 pm 11:45 PM

Start Spring using IntelliJIDEAUltimate version...

How to safely convert Java objects to arrays? How to safely convert Java objects to arrays? Apr 19, 2025 pm 11:33 PM

Conversion of Java Objects and Arrays: In-depth discussion of the risks and correct methods of cast type conversion Many Java beginners will encounter the conversion of an object into an array...

E-commerce platform SKU and SPU database design: How to take into account both user-defined attributes and attributeless products? E-commerce platform SKU and SPU database design: How to take into account both user-defined attributes and attributeless products? Apr 19, 2025 pm 11:27 PM

Detailed explanation of the design of SKU and SPU tables on e-commerce platforms This article will discuss the database design issues of SKU and SPU in e-commerce platforms, especially how to deal with user-defined sales...

How to use the Redis cache solution to efficiently realize the requirements of product ranking list? How to use the Redis cache solution to efficiently realize the requirements of product ranking list? Apr 19, 2025 pm 11:36 PM

How does the Redis caching solution realize the requirements of product ranking list? During the development process, we often need to deal with the requirements of rankings, such as displaying a...

See all articles