Java multithreading-lock, java Multithreading

Source: Internet
Author: User

Java multithreading-lock, java Multithreading

Since Java 5, the java. util. concurrent. locks package contains some locks, so you do not need to implement your own locks. But you still need to know how to use these locks.

A simple lock

Let's start with a synchronization block in java:

public class Counter{    private int count = 0;    public int inc(){        synchronized(this){            return ++count;        }    }}

We can see that there is a synchronized (this) code block in the inc () method. This code block ensures that only one thread can execute return ++ count at a time. Although the Code in the synchronization block of synchronized can be more complex, a simple operation like ++ count is enough to express the meaning of thread synchronization.

The following Counter classes use Lock instead of synchronized to achieve the same purpose:

public class Counter{    private Lock lock = new Lock();    private int count = 0;    public int inc(){        lock.lock();        int newCount = ++count;        lock.unlock();        return newCount;    }}

The lock () method locks the Lock instance object, so all threads that call the lock () method on this object will be blocked until the Lock Object's unlock () method is called.

Here is a simple implementation of the Lock class:

public class Counter{public class Lock{    private boolean isLocked = false;    public synchronized void lock()        throws InterruptedException{        while(isLocked){            wait();        }        isLocked = true;    }    public synchronized void unlock(){        isLocked = false;        notify();    }}

Note that the while (isLocked) loop is also called a "spin lock ". When isLocked is true, the thread that calls lock () blocks the wait on the wait () call. To prevent this thread from returning (also known as false wake-up) from wait () if it does not receive a call from notify ), this thread will re-check the isLocked condition to determine whether the current execution can be safely continued or need to be retained, instead of thinking that the thread can be safely resumed after it is awakened. If isLocked is false, the current thread will exit the while (isLocked) loop and set isLocked back to true, so that other threads that are calling the lock () method can Lock the lock instance.

When the thread completes the code in the critical section (between lock () and unlock (), it calls unlock (). When unlock () is executed, isLocked is set to false again, and one of the notifications (if any) calls wait () in the lock () method () function and the thread is in the waiting state.

Reentrant of the lock

The synchronized synchronization block in Java can be reentrant. This means that if a java thread enters the synchronized synchronization block in the code, and therefore obtains the lock on the pipe of the synchronization object used by the synchronization block, this thread can enter another java code block synchronized by the same pipe object. The following is an example:

public class Reentrant{    public synchronized outer(){        inner();    }    public synchronized inner(){        //do something    }}

Note that both outer () and inner () are declared as synchronized, which is equivalent to synchronized (this) block in Java. If a thread calls outer (), there is no problem in calling inner () in outer (), because these two methods (code blocks) all are synchronized by the same process object ("this. If a thread already has a lock on a pipe object, it has the right to access all the code blocks synchronized by the pipe object. This is reentrant. A thread can enter any code block that has synchronized locks.

The previous lock implementation is not reentrant. If we rewrite the Reentrant class as follows, when the thread calls outer (), it will block the lock. lock () of the inner () method.

public class Reentrant2{    Lock lock = new Lock();    public outer(){        lock.lock();        inner();        lock.unlock();    }    public synchronized inner(){        lock.lock();        //do something        lock.unlock();    }}

The thread that calls outer () will first Lock the Lock instance and then continue to call inner (). In the inner () method, this thread attempts to Lock the Lock instance again. As a result, this action will fail (that is, the thread will be blocked) because the Lock instance is already in the outer () method.

No unlock () is called between two locks (). The second call to lock will be blocked. After reading the lock () implementation, the cause is obvious:

public class Lock{    boolean isLocked = false;    public synchronized void lock()        throws InterruptedException{        while(isLocked){            wait();        }        isLocked = true;    }    ...}

Whether a thread is allowed to exit lock () is determined by the conditions in the while loop (spin lock. The current condition is that the lock operation is allowed only when isLocked is false, without considering which thread locks it.

To make the Lock class reentrant, we need to make a small change to it:

 

public class Lock{    boolean isLocked = false;    Thread  lockedBy = null;    int lockedCount = 0;    public synchronized void lock()        throws InterruptedException{        Thread callingThread =            Thread.currentThread();        while(isLocked && lockedBy != callingThread){            wait();        }        isLocked = true;        lockedCount++;        lockedBy = callingThread;  }    public synchronized void unlock(){        if(Thread.curentThread() ==            this.lockedBy){            lockedCount--;            if(lockedCount == 0){                isLocked = false;                notify();            }        }    }    ...}

Note that the current while loop (spin Lock) also takes into account the thread that has locked the Lock instance. If the current Lock object is not locked (isLocked = false), or the current call thread has locked the lock instance, The while loop will not be executed and Lock () will be called () the thread can exit this method (the Translator's note: "allowed to exit this Method" in the current syntax means that it will not call wait () and cause blocking ).

In addition, we need to record the number of times that the same thread repeatedly locks a lock object. Otherwise, an unblock () call will unlock the entire lock even if the current lock has been locked multiple times. We do not want the lock to be lifted until the number of times the corresponding lock () call has not been reached for the unlock () call.

Now this Lock class is reentrant.

Lock fairness

The Java synchronized blocks do not guarantee the order of the threads they are trying to enter. Therefore, if multiple threads are constantly competing to access the same synchronized synchronization block, there is a risk, one or more of the threads will never get access-that is, the access is always assigned to other threads. This situation is called thread hunger. To avoid this problem, the lock must be fair. The locks presented in this article are implemented using synchronized synchronization blocks internally, so they do not guarantee fairness.

Call unlock () in finally statements ()

If you use Lock to protect the critical section, and the critical section may throw an exception, it is very important to call unlock () in the finally statement. This ensures that the lock object can be unlocked so that other threads can continue to lock it. The following is an example:

lock.lock();try{    //do critical section code,    //which may throw exception} finally {    lock.unlock();}

This simple structure ensures that the Lock object can be unlocked when an exception is thrown in the critical section. If it is not the unlock () called in the finally statement, when an exception is thrown in the critical section, the Lock object will remain in the locked state forever, this will cause all other threads that call Lock () on the lock object to keep blocking.

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.