explicit lock

Lock和ReentrantLock:

Different from the built-in locking mechanism (synchronized), Lock provides an unconditional, pollable, timed and interrupted lock acquisition operation, and all locking and unlocking methods are explicit. The Lock interface method is declared as follows:

public interface Lock{
    void lock();
    void lockInterruptibly() throws InterruptedException;
    boolean tryLock();
    boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException;
    void unlock();
    Condition newCondition();
}

ReentrantLock implements the Lock interface and provides the same mutual exclusion and memory visibility as synchronized. When acquiring a ReentrantLock, it has the same memory semantics as entering a synchronized block; when releasing a ReentrantLock, it has the same memory semantics as exiting a synchronized block.

With ReentrantLock the lock must be released in the finally block. ReentrantLock is used as follows:

Lock lock = new ReentrantLock();
...
lock.lock();
try{
    ...
}finally{
    lock.unlock();
}

Polling locks, timed locks, and interrupt locks

The acquisition method of timed lock and polling lock is realized by the tryLock() method, which has a more complete error recovery mechanism than the acquisition method of unconditional lock.

In built-in locks, deadlock is a serious problem, the only way to recover the program is to restart the program, and the only way to prevent deadlock is to avoid inconsistent lock order when constructing the program. Timed and pollable locks offer another option: avoid deadlocks.

If you cannot acquire all the required locks, you can use a timed lock or a round-robin lock, which releases the acquired locks and retries to acquire all the locks.

Poll lock:

public boolean Polling(Account fromAcct, Account toAcct){
    while(true){
        if(fromAcct.lock.tryLock()){
            try{
                if(toAcct.lock.tryLock()){
                    try{
                        //业务逻辑
                    }finally{
                         toAcct.lock.unlock();
                    }
                }
            }finally{
                 fromAcct.lock.unlock();
            }
        }
    }
    return false;
}

Time lock:

public boolean trySendOnSharedLine(String message, long timeout, TimeUnit unit) throws InterruptedException{
    long nanosToLock = unit.toNanos(timeout) - estimatedNanosToSend(message);
    if(!lock.tryLock(nanosToLock, NANOSECONDS))
        return false;
    try{
        return sendOnShareLine(message);
    }finally{
        lock.unlock();
    }
}

Interrupt lock:

public boolean SendOnSharedLine(String message) throws InterruptedException{
    lock.lockInterruptibly();
    try{
        return cancellableSendOnShareLine(message);
    }finally{
        lock.unlock();
    }
}

fairness

The constructor of ReentrantLock provides two options for fairness: creating an unfair lock (the default) and creating a fair lock. Fair locks acquire locks in the order in which threads make requests; unfair locks allow "queuing": if a thread makes a request at the same time that the lock's state becomes available, the thread acquires the lock directly without queuing.

In most cases, unfair locks outperform fair locks. One reason: there is a large delay between resuming a suspended thread and the thread actually executing.

Fair locks should be used when locks are held for relatively long periods of time, or when the average time between requests for locks is long. The default built-in lock (synchronized) does not provide fairness guarantees.

Built-in locks and explicit locks:

ReentrantLock should only be used when some advanced features are required that cannot be implemented by built-in locks. These features include: timed, pollable and interruptible lock acquisition operations, fair queues, and non-block structured locks. Otherwise, the built-in lock (synchronized) should be used.

The non-block structure of ReentrantLock means that the operation of acquiring the lock cannot be associated with a specific stack frame, while the built-in lock can.

Read-write lock:

ReentrantLock is a strong mutual exclusion locking rule: only one thread is allowed to acquire the lock at a time. Although this rule avoids "read-write" conflicts and "write-write" conflicts, it also avoids "read-read" conflicts. But in fact, most of the operations on the data structure are read operations. How to relax the locking rules and allow multiple threads performing read operations to access the data structure at the same time, then you can use " read- write locks ": a resource can be read by multiple people at the same time. operation access, or access by a write operation, but not both at the same time.

ReadWriteLock和ReenReadWriteLock:

ReadWriteLock interface:

public interface ReadWriteLock{
    Lock readLock();
    Lock writeLock();
}

ReenReadWriteLock is the implementation class of ReadWriteLock. ReenReadWriteLock provides reentrant locking semantics for both types of locks. ReenReadWriteLock can also choose to be an unfair lock (default) or a fair lock during construction. The write lock of ReenReadWriteLock can have only one owner and can only be released by the thread that acquired the lock.

public class ReadWriteMap<K,V>{
    private final Map<K,V> map;
    private final ReadWriteLock lock = new ReenReadWriteLock();
    private final Lock r = lock.readLock();
    private final Lock r = lock.writeLock();

    public ReadWriteMap(Map<K,V> map){
        this.map = map;
    }

    public V put(K key,V value){
        w.lock();
        try{
            return map.put(key,value);
        }finally{
            w.unlock();
        }
    }

    public V get(Object key){
        r.lock();
        try{
            return map.get(key);
        }finally{
            r.unlock();
        }
    }  
}  

 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325297378&siteId=291194637
Recommended