Thread -- Lock Objects and Condition Objects

Lock Objects :

The basic outline for protecting  a code block with a "ReentrantLock" is :

myLock.lock();    //a ReentrantLock object
try {
    critical section
} finally {
    myLock.unlock();    //make sure the lock is unlocked even if an exception is throw
}

For Example:  (this code snippet references the simple program located at the bottom of this article)

package ConcurrentTest;

import java.util.Arrays;

/**
 * Created by lenovo on 2018/6/13.
 */
public class Bank {
    private final double[] accounts;
    private final Lock bankLock = new ReentrantLock();    //ReentrantLock implements the lock interface

    public Bank(int n, double initialBalance) {
        accounts = new double[n];
        Arrays.fill(accounts, initialBalance);
    }

    public void transfer(int from, int to, double amount) {
        bankLock.lock();    //the first thread that access this block will acquire the lock, 
                            //the others will wait this thread relinquishing the lock

        try {

            if (accounts[from] < amount) {
                return;
            }

            System.out.print(Thread.currentThread());
            accounts[from] -= amount;
            System.out.printf(" %10.2f from %d to %d", amount, from, to);
            accounts[to] += amount;
            System.out.printf(" Total Balance: %10.2f\n", getTotalBalance());
        } finally {
            bankLock.unlock();  //when the thread finishes, make sure to relinquish the lock 
                                //so that one of other threads can acquire the lock
        }
    }

    private double getTotalBalance() {
        double sum = 0;

        for(double account : accounts) {
            sum += account;
        }

        return sum;
    }

    public int size() {
        return accounts.length;
    }

}


Condition Objects :

A lock object can have one or more associated condition objects. You obtain a condition object with the "newCondition" method on the associating lock object. It is customary to give each condition object a name that evokes the condition that it represents. (with doing so, whenever we see the condition object, we will recogonize the meaning the condition represents). 

For example, consider the following code logic:  (this code snippet references the simple program located at the bottom of this article)

//The following code logic represents that the current thread will keeping deactivated 
//unless the account balance is sufficent to transfer.
Condition sufficientFunds = bankLock.newCondition();    //the condition object name should be meaningful.
                                                        //in this case, it represents that the accounts[from] must be
                                                        //sufficient for covering the amount to transfer
... ...
... ...
while (accounts[from] < amount) {
    sufficientFunds.await();    //after executing this method, the thread
                                //blocks, relinquishes the lock, and
                                //enters the awaiting set of the condition
}

With call the "await" method on the condition object (in this case it is "sufficientFunds"), the current thread blocks, and relinquishes the lock. When another thread access the critical code block, and call the "signalAll" method on the same condition object (in this case the condition object is "sufficientFunds"), all deactivated threads by the call to the "await" method are changed to be runnable, queue up to acquire the lock, and the scheduler will eventually activate them again.



The simple program simulates funds transfering from one account to another in a bank. We simulated an array of accounts transfering funds to each other randomly.

package ConcurrentTest;

import java.util.Arrays;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * Created by lenovo on 2018/6/13.
 */
public class Bank {
    private final double[] accounts;
    private Lock bankLock = new ReentrantLock();
    private Condition sufficientFunds = bankLock.newCondition();

    public Bank(int n, double initialBalance) {
        accounts = new double[n];
        Arrays.fill(accounts, initialBalance);
    }

    public void transfer(int from, int to, double amount) {
        bankLock.lock();

        try {

            while (accounts[from] < amount) {
                sufficientFunds.signal();
                sufficientFunds.await();
            }

            System.out.print(Thread.currentThread());
            accounts[from] -= amount;
            System.out.printf(" %10.2f from %d to %d", amount, from, to);
            accounts[to] += amount;
            System.out.printf(" Total Balance: %10.2f\n", getTotalBalance());
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            sufficientFunds.signalAll();
        } finally {
            sufficientFunds.signal();
            bankLock.unlock();
        }

    }

    private double getTotalBalance() {
        double sum = 0;

        for(double account : accounts) {
            sum += account;
        }

        return sum;
    }

    public int size() {
        return accounts.length;
    }

}
package ConcurrentTest;

/**
 * Created by lenovo on 2018/6/13.
 */
public class SynchBankTest {
    public static final int NACCOUNTS = 100;
    public static final double INITIAL_BALANCE = 1000;
    public static final double MAX_AMOUNT = 1000;
    public static final int DELAY = 10;

    public static void main(String[] args) {
        Bank bank = new Bank(NACCOUNTS, INITIAL_BALANCE);

        for (int i = 0; i < bank.size(); i++) {
            int fromAccount = i;

            Runnable r = () -> {
                try {
                    while (true) {
                        int toAccount = (int) (bank.size() * Math.random());
                        double amount = MAX_AMOUNT * Math.random();
                        bank.transfer(fromAccount, toAccount, amount);
                        Thread.sleep((int) (DELAY * Math.random()));
                    }
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            };

            new Thread(r).start();
        }

    }

}




猜你喜欢

转载自blog.csdn.net/liangking81/article/details/80715327
今日推荐