Two-phase termination mode of multithreaded programming

Source: Internet
Author: User
Tags finally block

For multithreaded programming, how gracefully terminating a child thread is always a worthy question. If you terminate a thread directly, you may have three problems:

    • The task that the child thread is currently performing may have to be executed atomically, either successfully or without execution;
    • There are still unfinished tasks in the current task queue, and terminating the threads directly may cause these tasks to be discarded;
    • The current thread consumes some external resources, such as opening a file, or using a socket object that is not garbage collected and must be cleaned by the caller.

This shows how gracefully terminating a thread is not a simple problem. A common way to terminate a thread is to declare a flag bit, if the caller wants to terminate the execution of the thread it creates, set the flag bit to a terminating state, and the child thread checks the flag bit before each execution of the task, and if it needs to terminate the state, it will not continue to perform the task. Instead, some cleanup work is done on resources consumed by the current thread, such as closing the socket and backing up the currently unfinished task, and ending the call to the current thread after the cleanup is complete.

The two-phase termination mode uses the above method to terminate the multithreading, but it encapsulates the termination of the thread into a specific framework, the user only needs to pay attention to the specific task execution mode, so that the termination of the thread and task execution of the separation of concerns. The UML diagram for the two-phase termination mode is as follows:

The role of the roles is as follows:

    • Threadowner: The client program, which creates the thread and executes the task, is also called by the terminatable to provide the terminating method;
    • Terminatable: An abstract interface provided by the termination method, providing a terminate () method for external invocation;
    • Terminatablesupport: Implements the abstract class of the Terminatable interface, encapsulates the concrete termination template, its dorun () is an abstract method, the subclass must implement, for writing the related task Code, dotermiate () and the Docleanup () method are hook methods that provide an empty implementation, and the subclass determines whether the method needs to be implemented according to the specific circumstances;
    • Concreteterminatable: A user-specific termination class whose Dorun () method is used to accomplish a specific task;
    • Terminationtoken: Contains a flag bit, and records the number of tasks that the current thread also needs to perform, by default, only its flag bit is true, and the remaining number of tasks that need to be performed is 0 o'clock to actually terminate the execution of the current thread.

The following is the implementation of each class of the two-phase termination pattern, and we first look at the Terminatable interface and its abstract implementation terminatablesupport:

publicinterface Terminatable {  voidterminate();}
 Public Abstract classTerminatablesupportextendsThreadImplementsterminatable { Public FinalTerminationtoken Terminationtoken;//Record the current flag bit   Public Terminatablesupport() { This(New Terminationtoken());//Initialize current flag bit} Public Terminatablesupport(Terminationtoken Terminationtoken) {Super(); This.Terminationtoken= Terminationtoken;//Initialize flag bitTerminationtoken.Register( This);//Register the current object's flag bit}protected Abstract void Dorun()throwsException;//methods for subclasses to implement specific tasks  //Hook method for sub-classes to do some cleanup work  protected void Docleanup(Exception cause) {}//Hook method, used for some custom operations when a subclass is terminated  protected void doterminate() {}@Override   Public void Run() {Exception ex =NULL;Try{//When performing a task in the current thread, it will determine if it is identified as terminated and the remaining number of tasks is less than or equal to 0 to actually terminate the current thread       while(!terminationtoken.Istoshutdown() || Terminationtoken.Reservations.Get() >0) {Dorun(); }    }Catch(Exception e)    {ex = e; }finally{Try{Docleanup(ex);//Actions to be performed when the front-end process terminates}finally{Terminationtoken.notifythreadtermination( This); }    }  }@Override   Public void Interrupt() {Terminate(); }@Override   Public void Terminate() {Terminationtoken.Settoshutdown(true);//Set termination status    Try{doterminate();//Perform client-side custom termination operations}finally{if(Terminationtoken.Reservations.Get() <=0) {Super.Interrupt();//If the current thread is in a signaled state, force the current thread to terminate}    }  }//provided to the client, that is, the client thread must wait until the termination is complete before continuing execution   Public void Terminate(Booleanwaituntilthreadterminated) {Terminate();if(waituntilthreadterminated) {Try{ This.Join(); }Catch(Interruptedexception e) {Thread.CurrentThread().Interrupt(); }    }  }}

When the client calls the Termiante () method, it first sets the current terminating state to true and then calls the Doterminate () method, and one thing to note here is that if the current thread is in a wait state in the Dorun () method, such as Thread.Sleep (), Thread.wait () method, and so on, it cannot be awakened even if the terminating state is set, because it cannot run to the code that detects the terminating state, it can only use the Intertupt () method to wake and terminate, but for the Socket.read () method, Even if the interrupt () method is called, it cannot be terminated, so the Doterminate () method is set here for subclasses to close the socket in the method. Finally, in the finally block, call the Super.interrupt () method, which also forces the execution of the current thread to terminate if it is blocked in the Dorun () method.

 Public classTerminationtoken {protected volatile BooleanToshutdown =false;flag bit for//termination status   Public FinalAtomicinteger reservations =NewAtomicinteger (0);//Record the number of currently remaining tasks  //Records all instances registered with Terminationtoken, where queue is used because there may be multiple  //terminatable instances share the same teraminationtoken, if they are shared, then reservations  The //instance saves the total number of tasks required to perform all threads that share the current Terminationtoken instance  Private FinalQueue<weakreference<terminatable>> coordinatedthreads; Public Terminationtoken() {coordinatedthreads =NewConcurrentlinkedqueue<> (); } Public Boolean Istoshutdown() {returnToshutdown; } Public void Settoshutdown(BooleanToshutdown) { This.Toshutdown= Toshutdown; }//Register the current terminatable instance in the current Terminationtoken  protected void Register(terminatable thread) {coordinatedthreads.Add(NewWeakreference<> (thread)); }//If multiple terminatable instances are registered to the current Terminationtoken,  //broadcasts the current termination state so that these instances are terminated  protected void notifythreadtermination(terminatable thread)    {weakreference<terminatable> wrthread; Terminatable Otherthread; while(NULL! = (Wrthread = coordinatedthreads.Poll()) {Otherthread = Wrthread.Get();if(NULL! = Otherthread && otherthread! = thread) {Otherthread.Terminate(); }    }  }}

The relationship between Terminatable and Terminationtoken is a one-to-many relationship where multiple terminatable instances can share a single terminationtoken instance, The Reservations property holds the number of tasks that are common to the multiple terminatable instances. A typical example of a Terminationtoken instance of multiple terminatable here is that when there are multiple worker threads, the tasks consumed by these threads are shared, and thus their termiantiontoken instances need to be shared.

The two-phase termination pattern is very much used, and basically it takes a certain way to gracefully terminate the execution of the thread as long as it is using a sub-thread position. Here we use the producer and consumer examples to demonstrate the use of the two-phase termination pattern, as shown in the code for this example:

 Public classSomeservice {Private Finalblockingqueue<string> queue =NewArrayblockingqueue<> ( -);Private FinalProducer Producer =New Producer();Private FinalConsumer Consumer =New Consumer(); Public Static void Main(string[] args)throwsinterruptedexception {Someservice SS =New Someservice(); Ss.Init(); Timeunit.SECONDS.Sleep( -); Ss.shutdown(); }//Stop producers and consumers from executing   Public void shutdown() {producer.Terminate(true);//Stop the producer and stop the consumer only after the producer has stopped completelyConsumer.Terminate();//Stop the consumer}//Start up producers and consumers   Public void Init() {producer.Start(); Consumer.Start(); }//producer  Private classProducerextendsTerminatablesupport {Private inti =0;@Override    protected void Dorun()throwsException {queue.put(String.valueOf(i++));//Add a task to the task queueConsumer.Terminationtoken.Reservations.Incrementandget();//Update the number of tasks that need to be performed}  }//Consumer  Private classConsumerextendsTerminatablesupport {@Override    protected void Dorun()throwsException {String Product = queue. Take();//Get TasksSystem. out.println("Processing product:"+ product);Try{Timeunit.SECONDS.Sleep(NewRandom ().Nextint( -));//Simulation of consumer execution of tasks}Catch(Interruptedexception e) {//Ignore}finally{Terminationtoken.Reservations.Decrementandget();//Update the number of tasks that need to be performed}    }  }}

As you can see, when you use the two-phase termination pattern for a subclass, it only needs to implement the tasks that you need to perform, and update the number of current tasks. In some cases, the number of current tasks can also not be updated, such as when terminating, do not care how many tasks are currently remaining to be executed.

Two-phase termination 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.