Java Multithreading (iii), thread synchronization

Source: Internet
Author: User

Java Multithreading (iii), thread synchronizationCategory: Javase comprehensive knowledge points 2012-09-18 17:59 2400 People reading reviews (0) favorite reports

Previously, thread creation and state control had been learned, but there was little or no significant connection between each thread. Sometimes, however, there may be multiple lines multithreading the same data, which may refer to a variety of strange problems. Learn more about multi-threaded control of data access now.

Because multiple threads of the same process share the same piece of storage space, it also poses a serious problem with access violations when it comes to convenience. The Java language provides a specialized mechanism to resolve this conflict, effectively avoiding the same data object being accessed by multiple threads concurrently.


One, multithreading caused by data access security issues

Here's a classic question about the question of bank money:

1), you have a bank card, there are 5000 dollars, and then you go to the cash machine to withdraw money, take out 3000, when you are taking, the teller machine has been found that you have 5000 dollars, and is preparing to subtract 300 dollars when

2), your wife takes that bank card corresponding passbook to the bank to withdraw the money, also must take 3000. Then the bank's system inquires, the Passbook account has 6000 (because the money is not deducted), so it is also ready to subtract 3000,

3), your card minus 3000,5000-3000=2000, and your wife's Passbook is also 5000-3000=2000.

4), as a result, you have taken a total of 6000, but the card has 2000 left.

Here's a look at the program's simulation process:

Package Com.tao.test;public class Getmoneytest {public static void main (string[] args) {Account account = new Account (5000 ); Getmoneyrun runnable = new Getmoneyrun (account), new thread (runnable, "you"). Start (); New Thread (runnable, "Your Wife"). Start ();}} Modeclass Account {private int money;public accounts (int money) {super (); This.money = money;} public int Getmoney () {return money;} public void Setmoney (int. money) {This.money = money;}} Runnable class Getmoneyrun implements Runnable {private account Account;public Getmoneyrun This.account = account;} @Overridepublic void Run () {if (Account.getmoney () >) {System.out.println (Thread.CurrentThread (). GetName () + " The account has "+ Account.getmoney () +" Yuan "), try {thread.sleep (),} catch (Interruptedexception e) {e.printstacktrace ();} int Lasetmoney=account.getmoney ()-3000;account.setmoney (Lasetmoney); System.out.println (Thread.CurrentThread (). GetName () + "took out 3000 yuan" + thread.currentthread (). GetName () + "account Plus" + Account.getmoney () + "Yuan");} else {System.out.println ("insufficient balance" + thread.currentthread (). GetName () + "account only" + Account.getmoney () + "Yuan");}}
Run the program multiple times, you can see a number of different results, the following are three of them:

Your account has $5000 your wife's account has $5000 your wife took it out of $3000 and your wife's account is $2000, and you've got $3000 out of your account and $1000.

Your account has $5000 your wife's account has 5000 dollars. Your wife took out $3000 and your wife's account--1000 yuan. You took out $3000 and your account--1000 yuan.

Your account has $5000 your wife's account has 5000 dollars. Your wife took out $3000 and your wife's account is $2000. You took out $3000 and you got $2000 in your account.

As you can see, two threads are accessing the account object at the same time, causing problems with the accounts that took the money. It is very easy to cause problems when multiple threads access the same data. To avoid this, we want to ensure that threads synchronize mutually exclusive, so-called synchronous mutual exclusion is: the concurrent execution of multiple threads at a certain time only allow a thread to execute to access the shared data.

Second, synchronous mutual exclusion lock

The principle of synchronous locks: Each object in Java has a built-in synchronization lock. In Java, you can use the Synchronized keyword to get a synchronous lock on an object. Synchronized is used in a block of code, plus synchronized (object) {...}

For example, there is a show method with synchronized code snippet:

public void Show () {    synchronized (object) {       ...    }}

This one of the objects can make any object that represents the current thread that obtains the lock on the object. An object has only one lock, so no other thread can access all of the code snippets that are included in the object by synchronized until the thread releases the synchronization lock on the object (the release lock refers to the lock thread exiting the synchronized synchronization method or block of code).

Note: There are several places to be aware of the use of synchronized (or an example of the Show method above):

①, the object that gets the sync lock is this, which is the current class object, which is one of the most used ways

public void Show () {    synchronized (this) {       ...    }}

②, adding synchronized to the method, which is called the synchronization method, is equivalent to the first method of the abbreviation
Public synchronized void Show () {   }

Synchronization of ③ and Static methods

public static synchronized void Show () {   }
Equivalent

public static void Show () {   synchronized (current class name. Class)}
Equivalent to acquiring a synchronous lock on a class object, noting that it is not the same as getting a synchronous lock on an object


Understand the principle of the synchronous lock and the use of synchronized keyword, then solve the above the problem of the money is very simple, we just add the Synchronized keyword inside the Run method is no problem, as follows:
@Override public    Void Run () {        synchronized (account) {            if (Account.getmoney () >) {                System.out.println (Thread.CurrentThread (). GetName () + "account has"                        + Account.getmoney () + "Yuan");                try {                    thread.sleep;                } catch (Interruptedexception e) {                    e.printstacktrace ();                }                int Lasetmoney = Account.getmoney ()-;                Account.setmoney (Lasetmoney);                System.out.println (Thread.CurrentThread (). GetName ()                        + "took out 3000 yuan" + thread.currentthread (). GetName ()                        + " The account also has "+ Account.getmoney () +" Yuan ");            } else {                System.out.println ("Insufficient balance"                        + thread.currentthread (). GetName () + "account only"                        + Account.getmoney () + "Yuan");}}}    


When a thread executes the Run method, it uses the synchronized (account) to obtain the synchronization lock of the account object, so long as it does not release the lock, then when the B thread executes to the Run method, it cannot get the lock that continues to execute. So you can only wait for a thread to execute, then release the lock, and then the B thread can continue execution.

Synchronized keyword use to note the following points:

1), can only synchronize methods and code blocks, and cannot synchronize variables and classes. As long as you protect the secure access and settings of the data in your class, you do not need to use the Synchronized keyword for the class, so Java does not allow this. And you want to synchronize the data, you only need to privatize the member variables, then synchronize the methods, do not need to use the member variable Synchronized,java also prohibit this.

2), each object has only one synchronous lock; when it comes to synchronization, what should be clearly synchronized? In other words, on which object is it synchronized? The Run method in the above code uses the synchronized (account) code block, because two threads are accessing the same user object, so they can be locked. But if it's another unrelated object, it's useless. For example, the synchronized (new Date ()) code block, just as no effect.

3), you do not have to synchronize all the methods in the class, the class can have both synchronous and non-synchronous methods.

4), if two threads are going to execute the synchronized method in a class, and two threads use the same instance to invoke the method, only one thread can execute the method at a time, and the other waits until the lock is freed. That is, if a thread obtains a lock on the object, no other thread can enter any one of the synchronization methods in the class (the object).

5), if the thread has synchronous and non-synchronous methods, the non-synchronous method can be freely accessed by multiple threads without being restricted by the lock.

6), when the thread sleeps, any sync locks it holds will not be released.
7), the thread can obtain multiple synchronization locks. For example, a synchronous method that invokes another object in a synchronous method of an object acquires a synchronous synchronization lock of two objects.
8), synchronization damage concurrency, should be as narrow as possible synchronization range. Synchronization can not only synchronize the entire method, but also synchronize some of the code blocks in the method.

9), write thread-safe code will make the overall efficiency of the system will be reduced, to moderate use

When a thread gets a sync lock, when does it get released?

1. Normal end of synchronization method or code block

2. Use return or break to terminate execution, or run out of unhandled exceptions.

3. When a thread executes a synchronous method or block of code, the program executes the Wait () method of the synchronization lock object.

Third, deadlock

Deadlock: Multiple threads are blocked at the same time, one or all of them waiting for a resource to be freed. The program is not functioning properly because the thread is blocked indefinitely. Simply put: When a thread is deadlocked, the first thread waits for the second thread to release the resource while the second thread waits for the first thread to release the resource. Here is a popular example: As on the sidewalk two people meet face to face, in order to give way to each other, two people at the same time to take a step, both sides can not pass, but also take a step to the other side, this still cannot pass. Let's say that this situation persists, so that there is a deadlock phenomenon.

The root cause of deadlocks is the inappropriate use of "synchronized" keywords to manage thread access to specific objects. The purpose of the "synchronized" keyword is to ensure that only one thread at a time is allowed to execute a particular block of code, so that the thread being allowed to execute must first have exclusive access to the variable or object. When a thread accesses an object, the thread locks the object, and the lock causes other threads that also want to access the same object to be blocked until the first thread releases the lock it adds to the object.

The cause of a deadlock is simple, such as having two objects A and B. The first thread locks A, then sleeps for 1 seconds, the second thread executes, the second thread locks B, and then sleeps for 1 seconds, then there is a turn to the first thread to execute. The first thread attempts to lock B, but B has been locked by the second thread, so the first thread goes into a blocking state and switches to the second thread execution. The second thread attempts to lock a, but a is already locked by the first thread, so the second thread also goes into a blocking state. In this way, a deadlock is caused.

As an example:

Package Com.tao.test;public class DeadLock2 {public static void main (string[] args) {Object Object1=new object (); object ob Ject2=new Object (); new Thread (New T (OBJECT1,OBJECT2)). Start (); new Thread (New T (Object2,object1)). Start ();}} Class T implements Runnable{private object Object1;private object Object2;public T (Object Object1,object object2) {THIS.O Bject1=object1;this.object2=object2;} public void Run () {synchronized (Object1) {try {thread.sleep ()} catch (Interruptedexception e) {e.printstacktrace () ;} Synchronized (object2) {System.out.println ("cannot perform to this step");}}};}
The top one is a deadlock.

The first thread first locks the object1 and then sleeps. Then the second thread locks the object2 and then sleeps. In the first thread attempts to lock the Object2, entering the block. Then the second thread attempts to lock the Object1 and go into a block. It's dead locked.

Four, the coordinated operation of the thread

With regard to the coordinated operation of threads, the classic example is the problem of producers and consumers. For example, there are producers continue to produce steamed bread, put into a basket, and consumers continue to take steamed bread from the basket to eat. And, when the basket is full, producers inform consumers to eat steamed bread, and they wait not to produce steamed bread. When the basket is not full, the consumer informs the producer to produce the steamed bread. Such a constant cycle.

In order to complete the above function, we can not complete the knowledge of the synchronization in front of us. Instead, it uses a coordinated run between threads. There are 3 ways to control the coordinated operation of threads in the top-level parent class object.

Notify, Notifyall, wait. Where wait has 3 overloaded methods.

These three methods must be called by the synchronization monitor object (that is, the lock object that the thread obtains), which can be divided into two situations:

1, for the synchronization code block with synchronized adornment, because the current class object (this) is the synchronization monitor, so you can call these three methods directly in the synchronous method.

2. For synchronous code blocks that use synchronized adornments, the synchronization monitor is an object that synchronized the parentheses, so you must use that object to call these three methods.

Wait (): Causes the current thread to wait until another thread calls the synchronization Monitor's notify () method or the Notifyall () method to wake the thread. The wait () method has three forms: wait with no time parameter (wait until other threads are notified), wait with a millisecond parameter, and wait with milliseconds, microseconds (both of which are automatically awakened after a specified time). The current thread that calls the wait () method releases the lock on the synchronization monitor.

Notify (): Wakes up a single thread waiting on this synchronization monitor. If all threads are waiting on this synchronization monitor, they will choose to fantasize about one of the threads. The choice is arbitrary. Other threads that wake up can only be executed when the front-thread discards the lock on the synchronization monitor (using the Wait () method).

Notifyall (): Wakes up all the threads waiting on this synchronization monitor. The wake-up thread can only be executed if the front-thread discards the lock on the synchronization monitor.

Because using the wait, notify, and Notifyall three methods must be used in a synchronous code block, be sure to understand the following points:

1, if two threads are to get the same object lock, which causes one of the threads to enter the blocking state. Then the blocked thread will have a chance to get the lock and continue executing the synchronized code block until the thread that gets the lock executes, or if it executes the wait method for the lock object.

2. A thread that uses the Wait method to enter a waiting state will release the lock. And only other threads invoke the Notify or Notifyall method to be awakened. Be aware that threads are different because of lock blocking and waiting because locks go into a blocking state, and locks are executed when other threads release the lock. While the wait state must be awakened by others, and the wake up is not necessarily immediately executed, it is possible because the Notifyall method causes many threads to wake up, multiple threads waiting for the same lock, and into the blocking state. It is also possible that the thread that called notify still does not release the lock, and the other thread will be able to compete for the lock until he is done.

Look at the following example:

Package Com.tao.test;public class Threada {public    static void Main (string[] args) {    runnabletest myrunnanle=new Runnabletest ();       New Thread (Myrunnanle). Start ();        Synchronized (Myrunnanle) {            try {                System.out.println ("First step");                Myrunnanle.wait ();            } catch (Interruptedexception e) {                e.printstacktrace ();            }            System.out.println ("Fourth Step");}}}    Class Runnabletest implements Runnable {public    void run () {    try {thread.sleep (1);} catch ( Interruptedexception e) {e.printstacktrace ();}        Synchronized (this) {            System.out.println ("Second Step");            Notify ();            System.out.println ("third Step");}}}    

There are two threads, the main thread and our own new child threads. A step-by-step analysis of the execution of the program:

1, because the child thread started, called sleep, so the main line enters upgradeable into the synchronization code block, and after the child thread because there is no lock, will enter the blocking state.

2, the main thread of the synchronization code block execution, print the first sentence, and then call the Wait method, enter the wait state. The lock is released because it enters the wait state, so the child thread can get the lock and start executing.

3, sub-thread execution, print the second sentence, and then call the Notify method, the main thread wakes. But the child thread does not end, still holds the lock, so the main thread has to go into blocking state, waiting for this lock.

4. The child thread prints the third sentence, and then the thread ends, releasing the lock. Then the main thread gets the lock, from blocking into the running state, print the fourth sentence.

5. Complete

Look at an example of the producers and consumers mentioned above:

First of all, is the production of the mode of goods, here with steamed bread Example:

Example of steamed bread class Mantou {private int id;//steamed bun idpublic mantou (int id) {this.id = ID;} Public String toString () {return ' Mantou ' +id;}}

Share the object, the producer produced the steamed bread into which the consumer takes out the steamed bread, here to basket example:

Basket instance, used to put steamed bread class BasketBall {private int index = 0;//to the first few steamed buns private mantou[] mantous = new mantou[6];//can put 6 steamed buns//Put Go in a steamed bun public synchronized void push (Mantou Mantou) {while (index==mantous.length) {try {System.out.println ("basket full! "); this.wait ();} catch (Interruptedexception e) {e.printstacktrace ();}} System.out.println (Thread.CurrentThread (). GetName () + "production" +mantou.tostring ()); This.notify (); Mantous[index] = mantou;index++;} Take a steamed bun public synchronized Mantou POPs () {while (index==0) {try {System.out.println ("Basket Empty! "); this.wait ();} catch (Interruptedexception e) {e.printstacktrace ();}} Mantou Mantou=mantous[--index]; System.out.println (Thread.CurrentThread (). GetName () + "ate" +mantou.tostring ()); This.notify (); return Mantou;}}

Producers:

Producer, production of steamed bread class Producer implements Runnable {private BasketBall basketball;public Producer (BasketBall BasketBall) { This.basketball = BasketBall;} @Overridepublic void Run () {for (int i = 0; i <; i++) {Mantou Mantou = new Mantou (i);//production of steamed bun Basketball.push (Mantou); try {thread.sleep;} catch (Interruptedexception e) {e.printstacktrace ();}}}}


Consumer, take steamed bread to eat class Consumer implements Runnable {private BasketBall basketball;public Consumer (BasketBall BasketBall) { This.basketball = BasketBall;} @Overridepublic void Run () {for (int i = 0; i <; i++) {Mantou mantou=basketball.pop (); try {thread.sleep ();} CATC H (interruptedexception e) {e.printstacktrace ();}}}}


Test:

public class Producerconsumer {public static void main (string[] args) {BasketBall basketball=new BasketBall (); New Thread ( New Producer (BasketBall)). Start (); New Thread (New Consumer (BasketBall)). Start ();}}

Java Multithreading (iii), thread synchronization (RPM)

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.