廖雪峰Java11多线程编程-3高级concurrent包-2ReadWriteLock

1.ReentrantLock的限制

ReentrantLock保证了只有一个线程能够执行临界区代码。 <font color="green">临界区代码:任什么时候候只有1个线程能够执行的代码块。 临界区指的是一个访问共用资源(例如:共用设备或是共用存储器)的程序片断,而这些共用资源又没法同时被多个线程访问的特性。当有线程进入临界区段时,其余线程或是进程必须等待,有一些同步的机制必须在临界区段的进入点与离开点实现,以确保这些共用资源是被互斥得到使用,例如:semaphore。只能被单一线程访问的设备,例如:打印机。</font>java

public void inc(){    
    lock.lock();
    try{
        value += 1;
    }finally{
        lock.unlock();
    }
}
public int get(){    
    lock.lock();
    try(){
        return value;
    }finally{
        lock.unlock();
    }
}

但有时候,这种保护有些过头:浏览器

  • 由于咱们发现任什么时候刻只容许1个线程修改,对inc()进行加锁是必须的。
  • 可是get()方法只读取数据,不修改数据。它应该容许多个线程同时调用。

咱们指望:容许多个线程同时读,但只要有一个线程在写,其余线程就必须等待。性能

2. ReadWriteLock

使用ReadWriteLock能够解决:this

  • 只容许一个线程写入(其余线程既不能写入,也不能读取)
  • 没有写入时,多个线程容许同时读(提升性能)
  • 实现
class Counter{
    final ReadWriteLock lock = new ReentrantReadWriteLock();
    //分别得到readLock和writeLock
    final Lock rlock = lock.readLock();
    final Lock wlock = lock.writeLock();
    private int value = 0;
    public void inc(){
        wlock.lock();
        try{
            value += 1;
        }finally {
            wlock.unlock();
        }
    }
    public int get(){
        rlock.lock();
        try{
            return this.value;
        }finally {
            rlock.unlock();
        }
    }
}

3.示例

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

class Count{
    private ReadWriteLock lock = new ReentrantReadWriteLock();
    private Lock rlock = lock.readLock();
    private  Lock wlock = lock.writeLock();
    private int value = 0;
    public void add(int m){
        wlock.lock();
        try{
            value += m;
        }finally {
            wlock.unlock();
        }
    }
    public void dec(int m){
        wlock.lock();
        try{
            value -= m;
        }finally {
            wlock.unlock();
        }
    }
    public int get(){
        rlock.lock();
        try{
            return value;
        }finally {
            rlock.unlock();
        }
    }
}
public class Main{
    final static int LOOP = 100;
    public static void main(String[] args) throws Exception{
        Count count = new Count();
        Thread t1 = new Thread(){
            public void run(){
                for(int i=0;i<LOOP;i++){
                    count.add(1);
                }
            }
        };
        Thread t2 = new Thread(){
            public void run(){
                for(int i=0;i<LOOP;i++){
                    count.dec(1);
                }
            }
        };
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        System.out.println(count.get());
    }
}

<img src="https://img2018.cnblogs.com/blog/1418970/201906/1418970-20190612202639771-792089703.png" width="500" />spa

ReadWriteLock适用条件:线程

  • 同一个实例,有大量线程读取,仅有少数线程修改。
  • 例如论坛帖子,回复视为写入,不频繁操做;浏览器看做读取,很是频繁。这种状况下,就能够适用ReadWriteLock

4. 总结:

使用ReadWriteLock能够提升读取效率:code

  • ReadWriteLock只容许一个线程写入。
  • ReadWriteLock容许多个线程同时读取。
  • ReadWriteLock适合读多写少的场景。
相关文章
相关标签/搜索