Java Multithreading (three) conditional objects

Source: Internet
Author: User

Reprint Please specify Source:http://blog.csdn.net/xingjiarong/article/details/47417383
In the previous blog, we learned to use Reentrantlock to control threads to access the same data, to prevent race Condition from appearing. This time. Let's continue in-depth study and learn about conditional objects in Java. Conditional objects are used more in multi-threaded synchronization.

First, let's introduce the critical section.

Critical section: In the program design of synchronization. A critical section is a program fragment that is used to access shared resources, and these shared resources have features that cannot be interviewed by multiple threads at the same time. When a thread enters a critical section, other threads or processes must wait, and in some cases, special methods must be used in the entry and exit points of the critical section. To ensure that these shared resources are mutually exclusive.

Now let's look at a new example, which is a sample of bank transfers. In the bank class, we declare an array of 10 sizes to represent 10 accounts in the bank. The corresponding value is the corresponding amount in this account. The bank provides a way to transfer the funds from the account, transferring amount funds to the to account. The method of obtaining the total amount of these accounts is also provided, GETTOTALBALABCE (), as the transfer of funds takes place in these 10 accounts, so no matter how it is transferred. The total amount should be the same.

Bank.java

ImportJava.util.concurrent.locks.ReentrantLock; Public  class Bank {    /** * Using arrays to simulate bank accounts * *    Private Final DoubleAccounts[];PrivateReentrantlock lock =NewReentrantlock (); Public Bank() {accounts =New Double[Ten];/ * Initialize so that each account is initially initialbalance money */         for(inti =0; I <Ten; i++) Accounts[i] = +; }/** * Method of transfer of funds * * @param from * source account * @param to * target accounts * @param Amount * Transfer Amount * *     Public void Transfer(intFromintTo,DoubleAmount) {Lock.lock ();Try{if(Accounts[from] < amount)returnSystem.out.print (Thread.CurrentThread ());            Accounts[from]-= amount; System.out.printf ("%5.2f from%d to%d", amount, from, to);            Accounts[to] + = amount; System.out.printf ("Total balance:%5.2f\n", Gettotalbalance ()); }Catch(Exception e)        {E.printstacktrace (); }finally{Lock.unlock (); }    }/** * Get the total amount of all accounts * * @return  * *     Public Double gettotalbalance() {lock.lock ();Doublesum =0;Try{ for(Doublea:accounts) sum + = A; }finally{Lock.unlock (); }returnSum }/** * Get the number of accounts today * * @return  * *     Public int size() {returnAccounts.length; }}

Transferrunnable This class implements the Runnable interface, we take him as a thread in the main function, and its run method is to generate a random target account and transfer the amount. Then call the Bank class method to transfer funds to the target account.

Transferrunnable.java

 Public  class transferrunnable implements Runnable{    PrivateBank Bank;Private intFromaccount; Public transferrunnable(Bank B,intfrom) {bank=b;    Fromaccount=from; } Public void Run(){Try{ while(true)            {intToaccount = (int) (Bank.size () *math.random ());DoubleAmount = +*math.random ();                Bank.transfer (Fromaccount, Toaccount, amount); Thread.Sleep ( +); }        }Catch(Exception e)        {E.printstacktrace (); }    }   }

In the main program, we created 10 threads, each of which transfers a certain amount of money from a corresponding account to a random account.
Main.java

 Public classMain { Public Static void Main(string[] args) {Bank b =NewBank (); thread[] Threadarray =Newthread[Ten]; for(inti =0; I <Ten; i++) {Threadarray[i] =NewThread (NewTransferrunnable (b, i)); } for(intI=0;i<Ten; i++) {Threadarray[i].start (); }    }}

In this program there are common variables-10 bank account funds, so there is a corresponding critical section of the--bank class of transfer method and GETTOTALBALABCE method, assuming that the incorrect critical section to protect, will cause multiple threads at the same time into the critical section, The result is wrong, the reader can test, will reentrantlock lock the place are removed, to see if the total amount will change, in my experiment, not only the total amount of money is not correct. Even the printed statement order is incorrect, indicating that a thread was interrupted by another thread in the process of System.out.printf ().

Look at this example, I believe you are more proficient in the use of Reentrantlock.

Now we're looking at the question of how, as you can see in the transfer method, if the amount of money in the account comes back immediately without a transfer of funds, I don't want to deal with it now. I want to do this, assuming the account is underfunded, wait until the other accounts transfer enough money to the account. Then the transfer of funds occurs.

The problem is. The thread that operates the account has been lock, the other threads are no longer able to enter the lock method, and it is impossible to transfer the corresponding funds to the account, so the thread must discard the lock control and let the other threads get it.

Java provides the conditional object, condition class, to cooperate with Reentrantlock to achieve the control of the critical section, we do the following changes to the Bank class.

ImportJava.util.concurrent.locks.Condition;ImportJava.util.concurrent.locks.ReentrantLock; Public  class Bank {    /** * Using arrays to simulate bank accounts * *    Private Final DoubleAccounts[];PrivateReentrantlock lock =NewReentrantlock ();PrivateCondition Condition; Public Bank() {accounts =New Double[Ten];/ * Initialize so that each account is initially initialbalance money */         for(inti =0; I <Ten; i++) Accounts[i] = +;    Condition = Lock.newcondition (); }/** * Method of transfer of funds * * @param from * source account * @param to * Account * @param Amount * Transfer Amount * *     Public void Transfer(intFromintTo,DoubleAmount) {Lock.lock ();Try{ while(Accounts[from] < amount) condition.await ();            System.out.print (Thread.CurrentThread ());            Accounts[from]-= amount; System.out.printf ("%5.2f from%d to%d", amount, from, to);            Accounts[to] + = amount; System.out.printf ("Total balance:%5.2f\n", Gettotalbalance ());        Condition.signalall (); }Catch(Exception e)        {E.printstacktrace (); }finally{Lock.unlock (); }    }/** * Get the total amount of all accounts * * @return  * *     Public Double gettotalbalance() {lock.lock ();Doublesum =0;Try{ for(Doublea:accounts) sum + = A; }finally{Lock.unlock (); }returnSum }/** * Get the number of accounts today * * @return  * *     Public int size() {returnAccounts.length; }}

First, an object reference variable condition of the condition class is declared, initialized in the bank's construction method. Initialization is the method that is called by the Reentrantlock class Newcondition (), which describes the condition object when it is dependent on the Reentrantlock object. A Reentrantlock object can create multiple conditional objects. Names are usually named in terms of control.

Then in the transfer method, the following two lines are key:

while (accounts[from] < amount)    condition.await();

Using the while loop to test the remaining amount of the account, assuming that the remaining amount is insufficient to invoke the await () method, the await () will block the thread and release the lock held by the thread. Other threads are then able to enter the critical section, and when the remaining amount of the account satisfies the condition, the waiting thread does not wake up actively until one of the threads invokes the Signalall () method. The Signalall () method wakes up all the threads that are waiting because the condition is not met, but the thread does not necessarily continue to run down, because when the Signalall () wakes up the thread, it does not tell the thread that your condition is satisfied, can continue to run down, but tells the thread, and now the condition changes, You can check again if the condition is satisfied. The assumption condition is satisfied. Then only one thread can continue to run down. As soon as one object obtains a lock on the critical section, the other threads cannot enter the critical section again.

So when should the Signalall () method be called, from experience should be called when the state of the object facilitates the direction of the waiting thread to change.

Here we re-transfer funds after the call, due to the transfer of funds. Other threads are likely to meet the conditions.

Note: usually. The call to await () should be in a loop body such as the following form:

whileto proceed))    condition.await();

The while loop here cannot be replaced with an IF condition statement, because the thread is awakened by another thread using the Signalall method, but the condition may be satisfied, not the condition must be satisfied. Assuming that a while loop continues to be checked, a thread that does not satisfy the condition continues to run downward, resulting in an error.

When a thread has a lock on a condition. It can only invoke await (), Signalall () on that condition. Signal () Three of these methods. Now let's talk about a third method.

The difference between signal and signalall is that signal will not wake up all the waiting threads. Instead of randomly selecting a thread to wake up, Signalall is waking up all of the waiting threads.

Finally attached source code: http://download.csdn.net/detail/xingjiarong/9010675

In the next blog post. I will introduce Java synchronized keyword, I hope to learn together with you progress, please continue to pay attention to my blog, if you support my words, on the top of me.

Java Multithreading (three) conditional objects

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.