Summary of multithreading design pattern (I.)

Source: Internet
Author: User

The programming and design of concurrent programs is a difficult point, and it is also one of the points that programmers must master. The first software written after work also has concurrent programming, at that time in the design concurrency this piece feels so complex, the final realization feel also a bit chaotic.

I wanted to learn a bit about the design of concurrent programming, but there was no time. This year read two concurrent programming related books, "Multithreaded design mode" and "Java concurrent programming and combat." This thinking and design patterns, multi-threaded design mode can also provide a lot of patterns to apply, but the actual situation is not so, multi-threaded design mode is based on many things, and the content has been a bit outdated, the market "multithreaded design mode" This book has been difficult to buy. And "Java Concurrent programming and combat" this book is more deep, also talk about the JAVA5 and contract the use of synchronous class. Personal feeling "multi-threaded design mode" Talk about things to understand, but the "Java Concurrency Programming Combat" is worth a fine read. Next I will write some blogs and readers to share my experience in reading these books.

Evaluation criteria for multi-thread-level

Evaluation criteria for multi-threaded threads:

    • 1) Security: No damage to objects

      Unsafe means that the state of an object is in an unexpected state, such as the account balance becomes negative

    • 2) Survivability: Carry out the necessary treatment

      Survivability refers to the normal operation of the program, the necessary processing can be done, affecting the survival of the typical problem of the deadlock has occurred

    • 3) reusability: Reusable class

      Reusability refers to code reuse, which can reduce duplication of code if reused

    • 4) Performance: Can be quickly, a lot of processing

      Performance has two aspects of consideration: throughput and responsiveness, client programs are more responsive, server-side programs pay more attention to throughput, throughput is the task that is done within a unit of time, and responsiveness refers to how long it takes to receive feedback from the program after the task is submitted. For example, when we QQ, often feel QQ card, this is the response of the problem.

Security and survivability are necessary, and if security and survivability are not guaranteed, there is no other consideration. Reusability and performance determine the quality of the program

The multi-threaded design mode is a total of 12 design patterns, listed below.

1) Single threaded execution

Only a single thread is allowed to execute a method of an object to protect multiple states of an object.

The implementation requires synchronized to modify the method that references the protected State so that only a single thread can access the method, and the other thread waits because the lock cannot be acquired because only one thread accesses the protected state variable, so there is no need to worry that the state variable is being modified by another thread.

You can also use synchronized to modify the code block to protect the status field.

Sample program:
1234567891011121314151617
public class Gate {    private String _name = "NoBody";    Private String _where = "NoBody"; Public    synchronized void Pass (string name, string where) {        _name = name;        _where = where;         Check ();    }    private void Check () {        if (_name.charat (0)! = _where.charat (0)) {             System.out.println ("***************** broken************** ");        }    } }

If there is no synchronized decorated pass method, there will be multiple threads executing the pass method at the same time in multi-threaded environment, which can cause inconsistent state and introduce security problem.

Applicable scenarios:

In a multithreaded environment, if the state variables (which may have multiple state variables and are related between them) are accessed by multiple threads and may change, you need to encapsulate the state variables (which can be encapsulated with classes) and protect the methods that access these state variables with synchronized. You can use synchronized to modify the method, or you can modify the code block.

Precautions:

It is important to note that synchronized is protecting state variables by acquiring which locks, and if a different lock object is used to protect the state variables, then multiple threads can still access the protected state variables, especially when protecting multiple related state variables, remember to use the same lock object. When synchronized modifies a method, the obtained lock object is an instance of the class that contains the Synchronied method, and the lock object that is obtained is also an instance of the current class when synchorized modifies this.

The synchronized modifier is not inherited, meaning that when we overwrite the Synchronized method of the parent class, the state variable cannot be protected without adding the synchronized modifier, so when overriding the parent class method, if you want to protect some state variables, Remember to add the synchronized modifier.

2) immutable

In the single threaded executetion mode we use synchronized to protect the state variables that need to be protected, because these states can change and can break objects if they are not protected. But using the synchronized protection variable also poses a performance problem, because acquiring a lock takes time, and if multiple threads compete for a lock, it causes some threads to enter the lock's conditional queue, pausing execution, which degrades performance.

If the state does not change at all, there is no need for lock protection, which is the immutable mode.

Sample program:
1234567891011121314151617181920212223
Public final class Person {    private final String _name;    Private final String _address; Public person    (string name, address of string) {        _name = name;        _address = address;    } Public    String GetName () {        return _name;    }    Public String getaddress () {        return _address;    }    @Override public    String toString () {        return ' person [_name= ' + _name + ", _address=" + _address + "]";    }}

The person class is final decorated to prevent inheritance.

_name and _address are both final modified, prevented from being modified, initialized only at the time of definition, or initialized in the constructor, and the person class provides only the get methods for these state fields, so the state cannot be modified when an instance of the class is called.

Applicable scenarios:

For those states that do not change, the immutable class can be encapsulated, which avoids synchronization with locks, which improves performance.

Precautions:

A string is a immutable class, and the corresponding StringBuilder or StringBuffer is the Muttable class. When we design a class, for instances that need to be shared and accessed very frequently, you can set it to the Immutalbe class, and if in a few cases its state may change, you can design the corresponding muttable class for it, like the relationship between string and StringBuffer.

StringBuilder is non-thread-safe, StringBuffer is thread-safe, and string is thread-safe because it is a immutable class.

The wrapper classes in Java are all immutable classes.

3) Guarded suspension

When we call a method of an object, it is possible that the current state of the object does not meet the conditions of execution, so we need to wait, which is guarded suspension mode. Only when the alert condition is met, it is executed, otherwise the object must have a way to change its state.

Sample program:
1234567891011121314151617181920
public class Requestqueue {    private final linkedlist<request> _queue = new linkedlist<request> ();    Public synchronized Request getrequest () {        while (_queue.size () <= 0) {            try {                wait ();            } catch (Interru Ptedexception e) {            }        }        return _queue.removefirst ();    }    Public synchronized void Putrequest (Request request) {        _queue.add (request);        Notifyall ();    } }

_queue.size () >0 is a warning condition, and only if _queue.size () >0 can call _queue.removefirst (), wait is required when the alert condition is not met.

The Putrequest method can change the state of the requestqueue so that the alert conditions in the Getrequest method are satisfied.

Applicable scenarios:

A caller's method executes when it wants to wait for the state to meet when the state is not satisfied, and executes immediately if the state satisfies, consider using guarded suspension mode.

Precautions:

The alert method in the guarded suspension (the method that waits for the state to be executed) is a synchronous block, and the thread that calls the method blocks when the state is not satisfied.

Guarded suspension in the state change method must remember that after the state change, call Notifyall, so that the thread that invokes the alert method can resume execution.

4) balking

The balking mode is similar to the guarded suspension mode, which requires some processing when the object state does not meet the requirements, but guared suspension waits and blocks the thread when the state does not meet the requirements, while the balking mode returns directly. Do not wait. The caller can temporarily do something else and then call the method of the object later.

Sample program:
123456789101112131415161718192021222324252627282930
public class Data {    private final String _file_name;    Private String _content;    Private Boolean _changed; Public    Data (string filename, string conetent) {        _file_name = filename;        _content = conetent;        _changed = false;    } Public    synchronized void change (String newcontent) {        _content = newcontent;        _changed = true;    } Public    synchronized void Save () throws IOException {        if (!_changed)            return;        Dosave ();        _changed = false;    }    private void Dosave () throws IOException {        writer writer = new FileWriter (_file_name);        Writer.write (_content);        Writer.close ();    } }

The Save method first detects whether the string has changed, returns immediately if there is no change, or saves the string, which avoids unnecessary IO and improves performance.

The alert condition in the above example is _changed to True

Applicable scenarios:

If you do not want to wait for alert conditions to be established, use balking mode.

The alert condition is suitable for use in balking mode only when it is first established.

Precautions:

This mode does not wait for the alert condition to be set up, and returns directly when the alert condition is not established, so the method of changing the state does not need to call the Notifyall method.

It is also important to note that both the method of vigilance and the way to change the state need to be synchronized with synchronized, because there are multiple data encapsulated, one for judging the state of the alert condition, and the real data.

5) Producer-consumer

Producer consumer problem is a very classic synchronization problem in the operating system, the producer produces good data, puts it into the buffer, and the consumer pulls out the data from the buffer. However, when the buffer is full, the producer can no longer put the produced data into the buffer, when the buffer has no data, the consumer can no longer withdraw data from the buffer.

The solution to producer consumer problems is called the producer consumer model, where there may be multiple producers, multiple consumers, producers and consumers with separate threads. The most critical of these is the buffer where the data is placed, producers and consumers must synchronize when the buffer is operating, and when the producer places the data in the buffer, if the buffer is found to be full then wait for the consumer to fetch data from the buffer if the buffer does not have data, and must wait.

Sample program:
12345678910111213141516171819202122232425262728293031323334
public class Table {private final string[] _buffer;private int _tail;private int _head;private int _count; T count) {_buffer = new String[count];_head = 0;_tail = 0;_count = 0;} public synchronized void put (String cake) throws in terruptedexception {while (_count >= _buffer.length) {wait ();} _buffer[_tail] = Cake;_tail = (_tail + 1)% _count;_count++;notifyall ();} Public synchronized String take () throws Interruptedexception {while (_count <= 0) {wait ();} String cake = _buffer[_head];_head = (_head + 1)% _count;_count--;notifyall (); return cake;}}

Table here is the role of the data buffer, when the consumer calls take data, if the number of data found less than 0 o'clock will wait, when the producer calls put to put data, if the number of data found larger than the buffer size, will also wait.

Applicable scenarios:

The producer-consumer model is appropriate when there are multiple producer roles in the program or multiple consumer roles operating on the same shared data. For example, the download module typically has multiple download task threads (consumer roles), which generate download tasks (producer roles) when the user clicks the download button, and they share the task queue.

Precautions:

Whether it is the production method or the consumption method, when the alert condition is not satisfied, must wait, the warning condition satisfies after executes to put the data logic or takes out the data logic, must call the Notifyall method, causes other threads to resume the operation.

6) Read-write Lock

In the previous multi-threaded design pattern, when the operation shared data, regardless of how to manipulate the data are mutually exclusive policy (in addition to the immutable mode), that is, only one thread is allowed to execute the synchronization method, the other threads in the condition queue of shared data wait, Only threads that are blocked after the thread that executes the synchronization method have finished executing the synchronization method can continue execution after the synchronization lock is acquired.

This is actually a bit low efficiency, because there is no mutual exclusion between read and read operations, two read threads can manipulate shared data concurrently, read threads and write threads concurrently manipulate shared data, and two write threads simultaneously manipulate the data to conflict.

Sample program:

Data class

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152
public class Data {private final char[] _buffer;         Private final Readwritelock _lock = new Readwritelock ();  public Data (int size) {_buffer = new char[size];    for (int i = 0; i < size; i++) _buffer[i] = ' * ';        }  public char[] Read () throws interruptedexception {_lock.readlock ();        try {return doread ();        } finally {_lock.readunlock ();        }}  public void write (char c) throws Interruptedexception {_lock.writelock ();        try {dowrite (c);        } finally {_lock.writeunock ();        }}  Private char[] Doread () {char[] newbuf = new Char[_buffer.length];        for (int i = 0; i < newbuf.length; i++) newbuf[i] = _buffer[i];        Slowly ();    return newbuf;            }  private void Dowrite (char c) {for (int i = 0; i < _buffer.length; i++) {_buffer[i] = C;        Slowly ();   } }  private void slowly () {try {thread.sleep (500);        } catch (Interruptedexception e) {e.printstacktrace (); }} }

Readwritelock class

12345678910111213141516171819202122232425262728293031323334353637
public class Readwritelock {private int _reading_readers = 0;    private int _waiting_writers = 0;    private int _writing_writers = 0; Private Boolean _prefer_writer = true;  public synchronized void Readlock () throws Interruptedexception {W Hile (_writing_writers > 0 | | (_prefer_writer && _waiting_writers > 0))        {Wait ();    } _reading_readers++;        }  public synchronized void Readunlock () {_reading_readers--;        _prefer_writer = true;    Notifyall ();        }  public synchronized void Writelock () throws interruptedexception {_waiting_writers++;        try {while (_reading_readers > 0 | | _writing_writers > 0) Wait ();        } finally {_waiting_writers--;    } _writing_writers++;        }  public synchronized void Writeunock () {_writing_writers--;        _prefer_writer = false;    Notifyall (); } }

A separate class Readwritelock,readwritelock for read-write locks is provided with 4 method Readlock,readunlock,writelock,writeunlock.

When a read thread reads shared data, it first calls the Readlock method to get the read lock, and then reads the shared data using the try block and calls Readunlock in the finnally block to release the read lock. When writing to shared data, the write thread first calls the Writelock method to get the write lock, and then writes the shared data using a try block and calls the Writeunlock method in the Finnally block to release the write lock.

_waiting_writers and _prefer_writer are used when implementing Readwritelock, but it is possible to implement read-write locks without the use of these two fields, but after using _prefer_writer, the read thread and the write thread are not hungry. Set _prefer_writer to True after each read thread has called Readunlock, at which point a write thread can resume execution instead of being executed by another read thread if it waits for the write to be written. Each time the write thread finishes calling Writeunlock, _prefer_writer is false, and the thread waiting to be read resumes execution.

Applicable scenarios:

The read-write lock mode can be used to improve program performance when the operation of shared data is significantly more than the write thread.

Precautions:

Java 5 Concurrent Package already has the Readwritelock interface, corresponding class has reentrantreadwritelock, do not need to implement Readwritelock class. The classes in the concurrency library are tested and stable, and the performance is higher than the classes you write, so we should prioritize the classes in the Concurrency library.

Reprint http://www.cloudchou.com/softdesign/post-609.html

Summary of multithreading design pattern (I.)

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.