Home  >  Article  >  Java  >  Detailed explanation of reentrancy locks and read-write locks in Java concurrency

Detailed explanation of reentrancy locks and read-write locks in Java concurrency

黄舟
黄舟Original
2017-09-26 09:50:061642browse

This article mainly introduces reentrancy locks and read-write locks in Java concurrent programming. The relevant example codes in the article are detailed and available for testing. It has certain reference value. Friends who need it can learn more.

Reentrancy lock

Reentrancy lock, as the name suggests, is a lock that supports reentry. It means that the lock can support repeated locking of resources by a thread. Re-entry means that any thread can acquire the lock again without being blocked by the lock after acquiring the lock. The implementation of this feature needs to solve the following two problems.

1. The thread acquires the lock again. The lock needs to identify whether the thread acquiring the lock is the thread currently occupying the lock. If so, it can be acquired successfully again.

2. The final release of the lock. The thread acquires the lock repeatedly n times, and then after releasing the lock for the nth time, other threads can acquire the lock. The final release of the lock requires the lock to increment the count for acquisition. The count indicates the number of times the current lock has been repeatedly acquired. When the lock is released, the count decrements. When the count equals 0, it means that the lock has been successfully released.

The built-in lock (synchronize) and Lock (ReentrantLock) in Java are both reentrant

##synchronized examples


package com.home;
public class SynchronizedTest implements Runnable {
  public synchronized void method1() {
    System.out.println("method1获得锁,正常运行!");
    method2();
  }
  public synchronized void method2() {
    System.out.println("method2获得锁,也正常运行!");
  }
  @Override
  public void run() {
    method1();
  }
  public static void main(String[] args) {
    SynchronizedTest st = new SynchronizedTest();
    new Thread(st).start();
    new Thread(st).start();
  }
}

#Lock Example


package com.home;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class LockTest implements Runnable {
  Lock lock = new ReentrantLock();
  public void method1() {
    lock.lock();
    System.out.println("method1获得锁,正常运行!");
    method2();
    lock.unlock();
  }
  public void method2() {
    lock.lock();
    System.out.println("method2获得锁,也正常运行!");
    lock.unlock();
  }
  @Override
  public void run() {
    method1();
  }
  public static void main(String[] args) {
    LockTest lt = new LockTest();
    new Thread(lt).start();
    new Thread(lt).start();
  }
}

The final results of both examples are correct, the results are as follows:


method1获得锁,正常运行!
method2获得锁,也正常运行!
method1获得锁,正常运行!
method2获得锁,也正常运行!

The biggest role of reentrant lock is to avoid deadlock

Read-write lock

The read-write lock maintains a pair of related locks, one for read-only operations and one for write operations. As long as there is no writer, the read lock can be held by multiple reader threads simultaneously. Write locks are exclusive.


Reentrant ReadWriteLock ReentrantReadWriteLock

The ReentrantReadWriteLock object provides readLock() and writeLock() methods for acquiring read locks and write locks.


The read lock allows multiple reader threads to hold it at the same time, while the write lock can only be held by at most one writer thread.


Read Use cases for write locks: The frequency of reading shared data is much greater than the frequency of modifying shared data. In the above situations, using read-write locks to control access to shared resources can improve concurrency performance.


If If a thread already holds a write lock, it can hold a read-write lock. On the contrary, if a thread already holds a read lock, it can no longer hold a write lock before releasing the read lock.


You can call the newCondition() method of the write lock to obtain the Condition object bound to the write lock. At this time, there is no difference from an ordinary mutex lock. However, calling the newCondition of the read lock () method will throw an exception.


Example


package com.home;
import java.util.Random;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
class ReadWrte {
  // 共享数据,可以多个线程读数据,只能有一个线程写数据
  private int data;
  // 创建读写锁
  ReadWriteLock rwLock = new ReentrantReadWriteLock();
  /**
   * 读数据,上读锁
   */
  public void get() {
    // 读锁
    rwLock.readLock().lock();
    try {
      System.out.println(Thread.currentThread().getName() + ",Read!");
      Thread.sleep((long) Math.random() * 1000);
      System.out.println(Thread.currentThread().getName() + " 读出的数据为:" +
        this.getData());
    } catch (Exception e) {
      e.printStackTrace();
    } finally {
      rwLock.readLock().unlock();
    }
  }
  /**
   * 写数据,上写锁
   *
   * @param data
   */
  public void put(int data) {
    // 写锁
    rwLock.writeLock().lock();
    try {
      System.out.println(Thread.currentThread().getName() + ",Write!");
      Thread.sleep((long) Math.random() * 1000);
      this.setData(data);
      System.out.println(Thread.currentThread().getName() + " 写入的数据为:" +
        this.getData());
    } catch (InterruptedException e) {
      e.printStackTrace();
    } finally {
      rwLock.writeLock().unlock();
    }
  }
  public int getData() {
    return data;
  }
  public void setData(int data) {
    this.data = data;
  }
}
/**
 * 测试类
 *
 * @author itmyhome
 *
 */
public class ReadWriteLockTest {
  /**
   * @param args
   */
  public static void main(String[] args) {
    // 创建ReadWrte对象
    final ReadWrte rw = new ReadWrte();
    for (int i = 0; i < 10; i++) {
      // 创建并启动10个读线程
      new Thread(new Runnable() {
          @Override
          public void run() {
            rw.get();
          }
        }).start();
      // 创建并启动10个写线程
      new Thread(new Runnable() {
          @Override
          public void run() {
            // 写入一个随机数
            rw.put(new Random().nextInt(8));
          }
        }).start();
    }
  }
}

The output is


Thread-0,Read!
Thread-4,Read!
Thread-8,Read!
Thread-12,Read!
Thread-0 读出的数据为:0
Thread-4 读出的数据为:0
Thread-8 读出的数据为:0
Thread-12 读出的数据为:0
Thread-19,Write!
Thread-19 写入的数据为:5
Thread-7,Write!
Thread-7 写入的数据为:7
Thread-3,Write!
Thread-3 写入的数据为:4
Thread-16,Read!
Thread-16 读出的数据为:4
Thread-11,Write!
Thread-11 写入的数据为:0
Thread-15,Write!
Thread-15 写入的数据为:5
Thread-2,Read!
Thread-2 读出的数据为:5
Thread-17,Write!
Thread-17 写入的数据为:2
Thread-6,Read!
Thread-6 读出的数据为:2
Thread-1,Write!
Thread-1 写入的数据为:5
Thread-13,Write!
Thread-13 写入的数据为:4
Thread-9,Write!
Thread-9 写入的数据为:7
Thread-5,Write!
Thread-5 写入的数据为:2
Thread-10,Read!
Thread-10 读出的数据为:2
Thread-18,Read!
Thread-14,Read!
Thread-18 读出的数据为:2
Thread-14 读出的数据为:2

We can see from the picture that multiple threads can read at the same time, but only one thread can write, that is, writing data and writing data are completed at the same time.

Summarize

The above is the detailed content of Detailed explanation of reentrancy locks and read-write locks in Java concurrency. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn