The protective suspend mode of multithreaded programming

Source: Internet
Author: User
Tags volatile

Protective suspend mode, also known as guarded suspension mode, refers to a condition that the current thread needs to check before executing a task, and the current thread can continue to perform the current task only if that condition is true. As the name implies, the protective suspend mode is a generalized concept with two main vectors: pre-conditions and tasks that can be used in any case where pre-checking is required.

1. Role description

Here is a description of each role location in the class diagram:

    • Guardedobject: Protected objects, which are supplied to client calls, are used to generate and execute protected behavior and to check and control state changes, as follows for each of its methods:
    • Guardedmethod (): Generates and executes the protected behavior;
    • Stateoperation (): Used to check whether the current state satisfies a specific state, thereby controlling the state of the protected behavior;
    • Blocker: This class primarily provides template methods, primarily for invoking protected behavior, or for waking threads that are currently waiting because of a priori condition that does not pass, as follows for each of its methods:
    • Callwithguard (guardedaction): This method first checks whether the guardedaction provided by the prior condition is satisfied, if not satisfied, it will block the current thread, otherwise the task in guardedaction will be executed;
    • Signalafter (Callable): This method first checks whether a priori condition is satisfied, and if a priori condition is met, it wakes up a waiting thread;
    • Broadcastafter (Callable): This method first checks whether a priori condition is satisfied, and if a priori condition satisfies, it wakes up all waiting threads;
    • Signal: Directly wakes up a thread that is waiting for a priori condition to be satisfied;
    • Broadcast (): Directly wakes up all the threads that are waiting for a priori condition to be satisfied;
    • Guardedaction: The carrier of the protected method, and provides the conditions for the prior inspection, the methods and properties of the following functions:
    • Predicate: Provides the conditions for the prior examination;
    • Call (): provides the tasks that need to be performed;
    • predicate: A condition that carries a prior condition check.
2. Example Demo

For example, we will encounter this scenario, in some operations, such as through the Elasticsearch server to query or update operations, we need to connect to the ES server, and before the ES server connection, all the query and update operations need to be blocked. Even after a server connection, we often need to do a heartbeat test on the server to check whether the connection to the server is still alive, if it does not survive, still need to continue to block the rest of the operation, and try to reconnect to the ES server, in this case we can use the protective suspend mode. The protective condition is that the connection to the ES server also survives, and if it does not survive, all threads that attempt to connect to the server are suspended, and the current thread attempts to connect to the server. Here is the sample code:

 Public classelasticsearchagent {Private volatile BooleanConnectedtoserver =false;Private Finalpredicate agentconnected = (), connectedtoserver;Private Finalblocker blocker =New Conditionvarblocker();Private FinalTimer Heartbeattimer =NewTimer (true); Public void Update(FinalUpdatecondition condition)throwsException {guardedaction<void> guardedaction =NewGuardedaction<void> (agentconnected) {@Override       PublicVoidPager() {doupdate(condition);return NULL;    }    }; Blocker.Callwithguard(guardedaction); }Private void doupdate(updatecondition condition) {Try{Timeunit.microseconds.Sleep( -);//Simulation for updates}Catch(Interruptedexception e) {e.Printstacktrace(); }  } Public void Init() {Thread Connectingthread =NewThread (New Connectingtask()); Connectingthread.Start(); Heartbeattimer.Schedule(New Heartbeattask(),60000, -); } Public void Disconnect() {connectedtoserver =false; }protected void onconnected() {Try{Blocker.Signalafter((), {connectedtoserver =true;returnBoolean.TRUE;    }); }Catch(Exception e) {e.Printstacktrace(); }  }protected void ondisconnected() {connectedtoserver =false; }Private classConnectingtaskImplementsRunnable {@Override     Public void Run() {Try{Thread.Sleep( -); }Catch(Interruptedexception e) {}onconnected(); }  }Private classHeartbeattaskextendsTimerTask {@Override     Public void Run() {if(!testconnection()) {ondisconnected();Reconnect(); }    }Private Boolean testconnection() {return true; }Private void Reconnect() {Connectingtask Connectingtask =New Connectingtask(); Connectingtask.Run(); }  }}

        can see that, in the update () operation, a Guardedaction object is created first, and the actual update operation is done in that object, The protective condition here is controlled by the variable connectedtoserver of a volatile type, which is set to true if the current connection to the ES server is still alive. Heartbeattask is a timed task that sends a heartbeat test to the server every 2s after the 60s delay to check if the connection is alive, and if it does not, it will set the Connectedtoserver variable to false and attempt to connect to the server. In the Init () method, you first create a task that connects to the server to ensure that the server connection is available at the initial time, and that it also initiates a timed task for the heartbeat test. The following is the implementation code for blocker and Conditionvarblocker:

publicinterface Blocker {  callWithGuardthrows Exception;  voidsignalAfterthrows Exception;  voidsignalthrows InterruptedException;  voidbroadcastAfterthrows Exception;}
 Public classConditionvarblockerImplementsBlocker {Private FinalLock lock;Private FinalCondition Condition; Public Conditionvarblocker(Lock Lock) { This.Lock= lock; This.condition= lock.newcondition(); } Public Conditionvarblocker() { This.Lock=NewReentrantlock (); This.condition= lock.newcondition(); }@Override   Public<V> VCallwithguard(guardedaction<v> guardedaction)throwsException {lock.lockinterruptibly();Try{FinalPredicate guard = guardedaction.Guard; while(!guard.Evaluate()) {condition.await(); }returnGuardedaction.Pager(); }finally{lock.Unlock(); }  }@Override   Public void Signalafter(callable<boolean> stateoperation)throwsException {lock.lockinterruptibly();Try{if(Stateoperation.Pager()) {condition.Signal(); }    }finally{lock.Unlock(); }  }@Override   Public void Signal()throwsinterruptedexception {lock.lockinterruptibly();Try{condition.Signal(); }finally{lock.Unlock(); }  }@Override   Public void Broadcastafter(callable<boolean> stateoperation)throwsException {lock.lockinterruptibly();Try{if(Stateoperation.Pager()) {condition.Signalall(); }    }finally{lock.Unlock(); }  }}

As you can see, Conditionvarblocker is basically a template code that declares a lock object and a Condition object, which is used to synchronize the current prior condition check process. The condition object is used to block the current thread if a priori condition is not satisfied.

In the Callwithguard () method, a loop is first checked to see if the current priori condition is satisfied, and if not, the current thread is put into a wait state and, if satisfied, the current thread continues to perform its task. It is important to note that we use the while () loop to determine if a priori condition is satisfied, because it is possible that the pre-condition is not satisfied when the front-end is awakened unexpectedly, or after being awakened, so the loop is used to make the current thread wait until the prior condition is not satisfied.

In the Signalafter () method, it first calls the Stateoperation.call () method to determine whether the current priori condition is satisfied and wakes up a waiting thread only if a priori condition is satisfied. Here stateoperation is a conditional vector that elasticsearchagent passed in to determine whether it is currently in a connected state.

The following is the implementation code for Guardedaction:

publicabstractclassimplements Callable<V> {  protectedfinal Predicate guard;  publicGuardedAction(Predicate guard) {    this.guard = guard;  }}

Here Guardedaction is an abstract class, which mainly encapsulates a predicate property. The main implementation of Guardedaction is generated in the Elasticsearchagent.guardedmethod () method, because the specific task to be performed needs to call Fangsheng, and here just provides a template method. The following is the code for predicate:

@FunctionalInterfacepublicinterface Predicate {  booleanevaluate();}

Here predicate is just a statement, its specific implementation is also in the elasticsearchagent, in this case, the main is to determine whether Connectedtoserver is true, that is, in the state of the connected server.

3. Guarded Suspension Implementation Considerations
    • can see the implementation of guarded suspension, where blocker, guardedaction, and predicate are just a template, which is mostly common code, And the code that is specific to the business is primarily in elasticsearchagent, which creates the Guardedaction object that is required to execute and controls the prior conditions it requires. Guarded suspension the separation of concerns, and when we use the pattern, we need to implement a client class that is similar to elasticsearchagent;
    • performs the use of the guarded Suspension mode, it should be noted that a Guardedaction object is created each time the Guardedobject.guardedmethod () method is executed, which can be a burden on the JVM garbage collection. Therefore, when using this mode, you need to pay special attention to the problem if the memory is small;
    • in guarded suspension mode, Conditionvarblocker Callwithguard () and signal* () The execution of the method is locking, because Conditionvarblocker is an object common to all threads, and its lock and condition variables are required to be uniformly visible by all threads, so it needs to be locked down;
    • In the Conditionvarblocker.callwithguard () method, the checking of a priori condition is done using a while loop, which is to prevent the waiting thread from being unexpectedly awakened, and the priori condition is not satisfied at this time. Use the while loop to ensure that the current thread is again in the wait state;
    • The above Conditionvarblocker also provides a constructor as follows:
publicConditionVarBlocker(Lock lock) {    this.lock = lock;    this.condition = lock.newCondition();}

This method is used to prevent the elasticsearchagent of nested monitors that may cause lock-in when a lock is required for some reason. The so-called nested monitor locking problem refers to the fact that if a thread executes two locks in turn, and because a priori condition is not satisfied, causing the current thread to release an inner lock to enter the wait state, while the other thread needs to acquire the outer lock to check the current priori condition, which leads to the lock cycle waiting problem. A thread that waits for a priori condition to hold an outer lock cannot be freed, and a thread attempting to change a priori condition is attempting to acquire an outer lock, but it has not been able to obtain it, resulting in a deadlock. In this case, the construction method is provided, and if elasticsearchagent needs to lock its method, it needs to pass the lock to conditionvarblocker through the construction method. This allows the current thread to release the lock while releasing both the outer lock and the inner lock (because it is the same lock).

The protective suspend mode of multithreaded programming

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.