Java Concurrency (Fundamentals)--Display lock and Sync tool classes

Source: Internet
Author: User
Tags semaphore throwable

Display lock

The lock interface is a new interface for Java 5.0, which is defined as follows:

Public interface Lock {    void lock ();    void Lockinterruptibly () throws interruptedexception;    Boolean trylock ();    Boolean Trylock (long time, Timeunit unit) throws interruptedexception;    void unlock ();    Condition newcondition ();}

Unlike the built-in locking mechanism, lock provides an unconditional, polling, timed, and interruptible Lock acquisition operation, all of which are displayed with lock and unlock methods. The Reentrantlock implements the lock interface, and the Reentrantlock has the following advantages over the built-in lock: The lock operation can be interrupted, and the time-out can be set when acquiring the lock. The following code gives the standard usage form of the lock interface:

Lock lock = new Reentrantlock (), .... Lock.lock (); try{...} finally {Lock.unlock ();

1.1, polling lock and timing lock

The timing and polling lock acquisition is implemented by the Trylock method, which has a perfect error response mechanism compared with the unconditional lock acquisition mode. The description of the Trylock method is as follows:

Boolean Trylock (): The lock is acquired only if the call to Shi is idle. If the lock is available, the lock is acquired and immediately returns the value TRUE. If the lock is not available, this method returns a value of false immediately.  Boolean Trylock (long time, Timeunit unit) throws Interruptedexception: Gets the lock if the lock is idle for a given wait time and the current thread is not interrupted. If the lock is available, this method returns the value immediately to true. If the lock is not available, the current thread is disabled for thread scheduling purposes, and the thread will remain dormant until one of the following three situations occurs: the lock is obtained by the current thread, or one of the other threads interrupts the current thread, or if a lock is received for the lock, or if the specified wait time has been obtained  The return value is true.  If the current thread: The interrupt state of the thread has been set when this method is entered, or if the lock is acquired and the interrupt acquired by the lock is supported, the interruptedexception is thrown and the current thread's interrupted state is cleared. If the specified wait time is exceeded, a value of false is returned. If time is less than or equal to 0, the method will not wait at all.

In the built-in lock, the deadlock is a serious problem, the only way to recover the program is to restart the program, and the only way to prevent deadlocks is to avoid inconsistent lock order when constructing the program, and can be timed with a polling lock provides another option: First use Trylock () to try to get all the locks, If you can't get all the locks you need, then release the lock you've acquired and try to get all the locks again, the following example shows how to use Trylock to avoid deadlocks: First use Trylock to get two locks, and if you can't get them at the same time, go back and try again.

    public boolean TransferMoney (account Fromacct, account Toacct, dollaramount amount, long timeout, timeunit unit) thro        WS Insufficientfundsexception, interruptedexception {long fixeddelay = 1;        Long randmod = 2;        Long stoptime = System.nanotime () + Unit.tonanos (timeout); while (true) {if (FromAcct.lock.tryLock ())} {try {if (ToAcct.lock.tryLock ()                                {try {if (fromacct.getbalance (). CompareTo (amount) < 0)                            throw new Insufficientfundsexception ();                                else {fromacct.debit (amount);                                Toacct.credit (amount);                            return true;                        }} finally {ToAcct.lock.unlock (); }}} finally {FRomAcct.lock.unlock ();            }} if (System.nanotime () < stoptime) return false;        Nanoseconds.sleep (Fixeddelay + rnd.nextlong ()% randmod); }    }

1.2. Interruptible Lock Acquisition operation

The Lockinterruptibly method is able to maintain a response to the interrupt while acquiring the lock, which is illustrated by the following:

void Lockinterruptibly () throws Interruptedexception: Gets the lock if the current thread is not interrupted. If the lock is available, the lock is acquired and returned immediately. If the lock is not available, the current thread is disabled for thread scheduling purposes, and until one of the following two scenarios occurs, the thread will remain dormant: The lock is obtained by the current thread, or some other thread interrupts the current thread, and supports the interrupt acquired by the lock. If the current thread: The interrupt state of the thread has been set when this method is entered, or if the lock is acquired and the interrupt acquired by the lock is supported, the interruptedexception is thrown and the current thread's interrupted state is cleared.

1.3. Read-write lock

In addition to adding the lock interface, Java 5 also adds the Readwritelock interface, the read-write lock, which is defined as follows:

Public interface Readwritelock {    Lock readlock ();    Lock Writelock ();}

A read-write lock allows multiple read threads to execute concurrently, but does not allow the write thread to execute concurrently with the read thread, nor does it allow the write thread to execute concurrently with the write thread. The following example uses the Reentrantreadwritelock wrapper map, which allows him to share securely among multiple threads:

public class Readwritemap <K,V> {private final map<k, v> Map;    Private final Readwritelock lock = new Reentrantreadwritelock ();    Private final Lock R = Lock.readlock ();    Private final Lock w = Lock.writelock ();    Public Readwritemap (map<k, v> map) {this.map = map;        } public V put (K key, V value) {W.lock ();        try {return Map.put (key, value);        } finally {W.unlock ();        }} public V remove (Object key) {W.lock ();        try {return map.remove (key);        } finally {W.unlock ();        }} public void Putall (map<? extends K,? extends v> m) {w.lock ();        try {Map.putall (m);        } finally {W.unlock ();        }} public void Clear () {w.lock ();        try {map.clear ();        } finally {W.unlock ();        }} public V get (Object key) {R.lock ();           try { return Map.get (key);        } finally {R.unlock ();        }} public int size () {r.lock ();        try {return map.size ();        } finally {R.unlock ();        }} public Boolean isEmpty () {r.lock ();        try {return map.isempty ();        } finally {R.unlock ();        }} public Boolean ContainsKey (Object key) {R.lock ();        try {return Map.containskey (key);        } finally {R.unlock ();        }} public Boolean containsvalue (Object value) {R.lock ();        try {return Map.containsvalue (value);        } finally {R.unlock (); }    }}

Synchronization Tool Class

2.1. Latching

Latching is a synchronous helper class that allows one or more threads to wait until a set of operations that are performed in another thread is completed.

Initializes the countdownlatch with the given count. Because the countdown () method is called, the await method is blocked until the current count reaches 0. After that, all the waiting threads are freed, and all subsequent calls to await are returned immediately. This behavior occurs only once-the count cannot be reset. If you need to reset the count, consider using Cyclicbarrier.

      The following example gives a common use of latching, testharness creating a certain number of threads, using them to perform the specified task concurrently, it uses two latching, The "Start gate" and "End Gate" are respectively indicated. The first thing each thread has to do is to wait on the startup door to make sure that all the threads are ready before they start executing, and that the final task for each thread is to subtract 1 from the countdown method that calls the end gate, which allows the main thread to wait efficiently until all the worker threads have finished executing, so you can count the time consumed:

public class Testharness {public long timetasks (int nthreads, final Runnable task        ) throws Interruptedexception {final Countdownlatch startgate = new Countdownlatch (1);        Final Countdownlatch endgate = new Countdownlatch (nthreads);                    for (int i = 0; i < nthreads; i++) {Thread t = new Thread () {public void run () {                        try {startgate.await ();                        try {task.run ();                        } finally {Endgate.countdown ();            }} catch (Interruptedexception ignored) {}}};        T.start ();        } Long start = System.nanotime ();        Startgate.countdown ();        Endgate.await ();        Long end = System.nanotime ();    return end-start; }}

2.2, Futuretask

Futuretask represents an asynchronous computation that can be canceled. This class provides a basic implementation of the future, taking advantage of the method of starting and canceling the calculation, the method of querying whether the calculation is complete, and the method of obtaining the result of the calculation. The result is only available when the calculation is complete, and if the calculation is not completed, the Get method is blocked. Once the calculation is complete, you cannot start or cancel the calculation again. The Futuretask method is summarized as follows:

Booleancancel (Boolean mayinterruptifrunning) attempted to cancel the execution of this task. Protected  Voiddone () invokes a protected method when this task transitions to a state isDone, whether normal or canceled. V get ()  throws Interruptedexception, executionexception if necessary, wait for the calculation to complete and then get its results. V get (long timeout, timeunit unit) throws Interruptedexception, executionexception, timeoutexception if necessary, Wait up to the time that the calculation is given to complete, and obtain its results if the results are available. Booleaniscancelled () returns True if it is canceled before the task is completed properly. Booleanisdone () returns True if the task is completed. Voidrun () set it as the result of its calculation unless the future is canceled. Protected  Booleanrunandreset () performs the calculation without setting its results, resets the future to its original state, and fails if the calculation encounters an exception or is canceled. Protected  Voidset (v V) Set the result to the given value unless the future has been set or canceled. Protected  voidsetexception (Throwable t) unless this future has been set or canceled, it will report a executionexception and will give the given throwable its cause.

Futuretask can be used to represent long calculations that can be started before using the results of the calculation, the following code simulates a high-overhead calculation, we can start the calculation by calling the start () method, and then call get to get the result when we need the result:

public class Preloader {ProductInfo Loadproductinfo () throws dataloadexception {return null;} Private final futuretask<productinfo> future = new Futuretask<productinfo> (New Callable<productinfo > () {public productinfo call () throws Dataloadexception {return loadproductinfo ();}); Private final thread thread = new Thread (future);p ublic void Start () {Thread.Start ();} Public ProductInfo get () throws Dataloadexception, Interruptedexception {try {return future.get ();} catch ( Executionexception e) {throwable cause = E.getcause (); if (cause instanceof dataloadexception) throw (dataloadexception) Cause;elsethrow new RuntimeException (e);}} Interface ProductInfo {}}class dataloadexception extends Exception {}

2.3. Signal Volume

Conceptually, semaphores maintain a set of licenses. If necessary, block each acquire () before the license is available, and then wait for the license. Each release () adds a license that may release a blocked fetch. However, instead of using the actual license object, Semaphore only counts the number of available licenses and takes action accordingly.

Semaphore is typically used to limit the number of threads that can access certain resources (physical or logical). For example, the following class uses semaphores to control access to a content pool:

Class Pool {private static final int max_available = 100;   Private final Semaphore available = new Semaphore (max_available, true);     Public Object GetItem () throws Interruptedexception {Available.acquire ();   return Getnextavailableitem ();   } public void PutItem (Object x) {if (markasunused (x)) available.release (); }//Not a particularly efficient data structure; Just for demo protected object[] items = ... whatever kinds of items being managed protected boolean[] used = new bool   Ean[max_available]; Protected synchronized Object Getnextavailableitem () {for (int i = 0; i < max_available; ++i) {if (!used[i]          ) {Used[i] = true;       return items[i]; }} return null; Not reached} protected synchronized a Boolean markasunused (Object item) {for (int i = 0; i < max_available;            ++i) {if (item = = Items[i]) {if (Used[i]) {Used[i] = false;          return true;   } else         return false;   }} return false; } }

Before obtaining an entry, each thread must obtain a license from the semaphore, thereby guaranteeing that the item can be used. After the thread finishes, the item is returned to the pool and the license is returned to that semaphore, allowing other threads to get the item. Note that it is not possible to maintain a synchronous lock when calling acquire () because it prevents the item from being returned to the pool. Semaphores encapsulate the required synchronization to limit access to the pool, which is separate from the synchronization required to maintain the consistency of the pool itself.

Initializes the semaphore to 1 so that it can be used as a mutually exclusive lock with a maximum of one license available at the time of use. This is often referred to as a binary semaphore because it can only have two states: one available license, or 0 licenses available. When used in this manner, the binary semaphore has some attribute (different from many lock implementations), that is, the "lock" can be freed by the thread, rather than by the owner (because the semaphore has no ownership concept). This can be useful in some specialized contexts, such as deadlock recovery.

Semaphore's construction method optionally accepts a fair parameter. When set to False, this class does not guarantee the order in which a thread acquires a license. In particular, intrusion is allowed, meaning that a thread that calls acquire () can be assigned a license before the waiting thread, logically, that the new thread will put itself on the head of the waiting thread queue. When the fairness is set to true, the semaphore guarantees that for any thread that invokes the fetch method, the thread is selected and licensed according to the order in which they are invoked (that is, first-out, FIFO). Note that FIFO sorting is necessarily applied to the specified internal execution point within these methods. Therefore, a thread may have called acquire before another thread, but it has reached the sort point after that thread, and is similar when returning from the method. Also note that the non-synchronous Tryacquire method does not use fair settings, but uses any available license.

In general, the amount of semaphores used to control resource access should be initialized to be fair to ensure that resources are accessible to all threads. When using semaphores for other kinds of synchronization control, the throughput benefits of unfair sequencing are usually more important than fairness considerations.

Semaphore also provides a convenient way to acquire and release multiple licenses at the same time. Caution, using these methods when the fairness is not set to true increases the risk of indeterminate delays.

Memory consistency effect: the operation before the "release" method (such as release ()) is called in the thread, followed by a successful "get" method (such as Acquire ()) in the other happen-before.

2.4. Fence

Cyclicbarrier is a synchronous helper class that allows a set of threads to wait for each other until a common barrier point is reached. In programs that involve a set of fixed-size threads, these threads have to wait for each other, and cyclicbarrier is useful at this time. Because the barrier can be reused after releasing the waiting thread, it is called a cyclic barrier.

Cyclicbarrier supports an optional runnable command that runs only once at each barrier point after the last thread in a set of threads arrives (but before releasing all threads). This barrier operation is useful if you update the shared state before continuing with all participating threads.

Example usage: Here is an example of using barrier in a parallel decomposition design:

Class Solver {final int n;final float[][] data;final cyclicbarrier barrier;class Worker implements Runnable {int myrow; Worker (int row) {myrow = row;} public void Run () {!done ()) {Processrow (myrow); try {barrier.await ();} catch (Interruptedexception ex) {return;} CA TCH (Brokenbarrierexception ex) {return;}}}} Public Solver (float[][] matrix) {     data = matrix;     N = matrix.length;     Barrier = new Cyclicbarrier (N,                      new Runnable () {public                       void run () {                          //mergerows (...)}                     );     for (int i = 0; i < N; ++i)        New Thread (New Worker (i)). Start ();     Waituntildone ();   }}

In this example, each worker thread processes a row of the matrix, and the thread waits at the barrier until all rows have been processed. After all the rows are processed, the provided Runnable barrier operations are performed and the rows are merged. If the Consolidator determines that a solution has been found, then done () will return true, and all worker threads will be terminated.

If the barrier operation does not depend on the thread that is being suspended when it executes, any thread in the thread group can perform the operation when it has been released. To facilitate this operation, each call to await () returns the index of the thread that can reach the barrier. You can then choose which thread should perform the barrier operation.

For failed synchronization attempts, Cyclicbarrier uses a break mode that is either all or none (All-or-none): If the thread leaves the barrier prematurely because of a break, failure, or timeout, all other threads waiting at that barrier will also pass The brokenbarrierexception left in an unnatural way.

Memory consistency effect: actions before an await () call in a thread happen-before those that are part of the barrier operation, which in turn Happen-before the operation that was successfully returned from another thread that corresponds to an await ().

Java Concurrency (Fundamentals)--Display lock and Sync tool classes

Related Article

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.