Learn Java multi-thread synchronization _java

Source: Internet
Author: User
Tags ticket java se

If your Java base is weak, or you don't know much about Java multithreading, read this article "Learning Java threads thread definition, status, and properties"

Synchronization has always been a pain in Java multithreading, and it's rarely used when we do Android development, but that's not why we're not familiar with synchronization. Hopefully this article will enable more people to understand and apply Java synchronization.
In multi-threaded applications, two or more than two threads need to share access to the same data. This is often a competitive condition if two threads access the same object, and each thread invokes a method that modifies the object.
The easiest examples of competitive conditions are: Trains sell tickets, train tickets are certain, but the windows that sell train tickets are everywhere, and each window is equivalent to a thread, and so many threads share all the train ticket resources. and cannot guarantee its atomicity, if at a point in time, two threads use this resource simultaneously, they take out the train ticket is the same (seat number), which will cause trouble to passengers. The solution is that when a thread is going to use a train ticket for this resource, we give it a lock, and when it finishes, it locks the lock to another thread that uses the resource. This will not happen.

1. Lock Object
the Synchronized keyword automatically provides locks and associated conditions, most of which require an explicit lock to be used synchronized very handy, but when we understand Reentrantlock class and condition objects, We can better understand the synchronized keyword. Reentrantlock is introduced in Java SE 5.0, the structure of a block of code protected with Reentrantlock is as follows:

Mlock.lock ();
try{...
}
finally{
Mlock.unlock ();
}

This structure ensures that only one thread enters the critical section at any moment and that no other thread can pass the lock statement once a thread has blocked the lock object. When other threads call lock, they are blocked until the first thread releases the lock object. It is necessary to put the unlocked operation in Finally, if an exception occurs in the critical section, the lock must be released, otherwise the other threads will block forever.

2. Condition Object
When entering a critical section, it is found that after a certain condition is satisfied, it can be executed. To use a conditional object to manage a thread that has acquired a lock but cannot do useful work, the condition object is also called a condition variable.
Let's take a look at the following example to see why you need a conditional object

Suppose a scenario we need to transfer by bank, we first write the bank's class, its constructor requires incoming account number and account amount

public class Bank {
private double[] accounts;
  Private Lock Banklock;
  Public Bank (int n,double initialbalance) {
    accounts=new double[n];
    Banklock=new Reentrantlock ();
    for (int i=0;i<accounts.length;i++) {accounts[i]=initialbalance}}}
  

Next we're going to withdraw, write a method of withdrawal, from is the transfer party, to is the receiver, amount transfer amount, the result we found that the balance of the transfer is insufficient, if there are other threads to the transfer to save enough money to transfer the success, but this thread has acquired the lock, it has exclusive, Other threads are unable to acquire locks for deposit operations, which is why we need to introduce conditional objects.

  public void Transfer (int from,int to,int amount) {
    banklock.lock ();
    try{while
      (accounts[from]<amount) {
        //wait
      }
    }finally {
      banklock.unlock ();
    }
  }

A lock object has several related condition objects, can obtain a condition object with Newcondition method, we get the conditional object and call the await method, the current thread is blocked and the lock is abandoned.

public class Bank {
private double[] accounts;
  Private Lock Banklock;
  Private Condition Condition;
  Public Bank (int n,double initialbalance) {
    accounts=new double[n];
    Banklock=new Reentrantlock ();
    Get the Condition Object
    condition=banklock.newcondition ();
    for (int i=0;i<accounts.length;i++) {
      accounts[i]=initialbalance
    }
  }
  public void Transfer (int from,int to,int amount) throws Interruptedexception {
    banklock.lock ();
    try{while
      (accounts[from]<amount) {
        //block the current thread and discard the lock
        condition.await ();
      }
    finally {
      banklock.unlock ();}}}

Threads waiting to acquire a lock are essentially different from the thread that calls the await method, and once a thread invokes the await method, he will enter the waiting set for that condition. When a lock is available, the thread cannot unlock it immediately, instead he is in a blocking state until another thread invokes the Signalall method on the same condition. When another thread prepares to transfer to our previous transfer party, just call Condition.signalall (), and the call will reactivate all threads waiting for this condition.
When a thread invokes the await method, he cannot reactivate itself and expects to invoke the Signalall method on the other thread to activate itself, and if no other threads activate the waiting thread, then a deadlock occurs, and if all other threads are blocked, When the last active thread calls await before it unlocks another thread, it is blocked, and no thread can unblock other threads and the program is suspended.
When does the call Signalall? Normally it should be useful to invoke signalall when the direction of the waiting thread changes. In this example, when an account balance is changed, the waiting thread should have an opportunity to check the balance.

 public void Transfer (int from,int to,int amount) throws Interruptedexception {
    banklock.lock ();
    try{while
      (accounts[from]<amount) {
        //blocks the current thread and discards the lock
        condition.await ();
      }
      Operation of transfer ...
      Condition.signalall ();
    } finally {
      banklock.unlock ();
    }
  }

When the Signalall method is invoked, it does not immediately activate a waiting thread, it simply unlocks the waiting thread so that the threads can access the object through competition after the current thread exits the synchronization method. Another method is signal, which is randomly unblocking a thread, and if the thread is still not running, it is blocked again, and if no other thread calls signal again, the system is deadlocked.

3. Synchronized keyword
The lock and condition interfaces provide a high degree of lock control for program designers, but in most cases they do not require such control and can be used in a mechanism embedded within the Java language. Starting with the Java1.0 version, each object in Java has an internal lock. If a method is declared with a synchronized keyword, the lock of the object protects the entire method. In other words, to invoke the method, the thread must obtain an internal object lock.
Other words

Public synchronized void Method () {

}

Equivalent to

public void Method () {
this.lock.lock ();
try{

}finally{
this.lock.unlock ();
}

In the example above, we can declare the transfer method of the Bank class as synchronized instead of using a display lock.
Internal object locks have only one dependent condition, wait amplification is added to a thread to the wait set, the Notifyall or notify method unlocks the blocking state of the waiting thread. That is, wait is equivalent to calling condition.await (), notifyall equivalent to Condition.signalall ();

The above example transfer method can also be written like this:

  Public synchronized void Transfer (int from,int to,int amount) throws interruptedexception{while
    (Accounts[from) <amount) {wait
      ();
    }
    Operation of transfer ...
    Notifyall ();  
    }

You can see that using the Synchronized keyword to write code is a lot simpler, of course, to understand this code, you have to understand that each object has an internal lock, and the lock has an internal condition. Locks are used to manage threads that attempt to enter the synchronized method, and conditions govern the threads that call wait.

4. Synchronous blocking
As we said above, each Java object has a lock, the thread can invoke the synchronization method to obtain the lock, and another mechanism can obtain the lock by entering a synchronization block when the thread enters the following form of blocking:

Synchronized (obj) {

}

So he got the lock of obj. Let's look at the bank class.

public class Bank {
private double[] accounts;
Private Object Lock=new object ();
  Public Bank (int n,double initialbalance) {
    accounts=new double[n];
    for (int i=0;i<accounts.length;i++) {
      accounts[i]=initialbalance
    }
  }
  public void Transfer (int from,int to,int amount) {
    synchronized (lock) {
     //Transfer Operation
      ...
    }
}}

In this case, the lock object is created to use only the locks held by each Java object. Sometimes developers use a lock on an object to implement additional atomic operations, called client-side locking. For example, the vector class, its method is synchronous. Now assume that the bank balances are stored in vectors

 public void Transfer (Vector<double>accounts,int from,int to,int amount) {
 Accounts.set ( from)-amount);
 Accounts.set (To,accounts.get (to) +amount;
}

The Get and set methods for the Vecror class are synchronized, but this does not help us. After the first execution of a get call, a thread may well be deprived of the right to run in the transfer method, so another thread may have stored a different value in the same storage location, but we can intercept the lock

 public void Transfer (Vector<double>accounts,int from,int to,int amount) {
 synchronized (accounts) {
 Accounts.set (From,accounts.get (from)-amount);
 Accounts.set (To,accounts.get (to) +amount;
 }
}

Client-side locking (synchronized code blocks) is very fragile and is generally not recommended, and general implementation synchronization is best achieved with classes provided under the Java.util.concurrent package, such as blocking queues. If the synchronization method is appropriate for your program, use the Sync method as much as possible, he can reduce the number of code written, reduce the chance of error, and use Lock/condition if you specifically need to use the unique features provided by the lock/condition structure.

The above is the entire content of this article, I hope to help you learn.

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.