Java 复习 —— 锁以及线程之间的通讯

时光总嘲笑我的痴心妄想 提交于 2019-12-03 05:54:59


1、Lock

1)1.5版本之后出现,java.util.concurrent.locks.Lock

2) Lock 实现提供了比使用 synchronized 方法和语句可获得的更广泛的锁定操作。此实现允许更灵活的结构,可以具有差别很大的属性,可以支持多个相关的 Condition 对象。 锁是控制多个线程对共享资源进行访问的工具。通常,锁提供了对共享资源的独占访问。一次只能有一个线程获得锁,对共享资源的所有访问都需要首先获得锁。不过,某些锁可能允许对共享资源并发访问,如 ReadWriteLock 的读取锁。 

3)一般使用的Lock替代synchronized的代码如下:

     private Lock l = new ReentrantLock(); 
     l.lock();
     try {
         // access the resource protected by this lock
     } finally {
         l.unlock();
     }

4)和synchronized一样,也可以在线程之间进行通讯,如下代码:

class Data {
    private int number = 0;// 共享变量
    private Lock lock = new ReentrantLock(); // 一种互斥锁
    private Condition c1 = lock.newCondition(); // 锁上的一个条
    private Condition c2 = lock.newCondition(); // 锁上的另一个条件
    
    public Data(){
        System.out.println( c1 == c2); // 返回false,一个lock可以拥有多个独立的condition
    }
    
    public int increase(){
        lock.lock();// 对共享变量的操作必须加锁,而且线程通讯必须在拥有的锁的基础上
        try{
            if(number != 0){ // 这里没有必要使用循环判断,但是Object.wait必须在循环中判断
                try {
                    c1.await(); // 如果调用c1的方法,那么后面满足条件就应该对应唤醒c1
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            number++;
            c2.signal(); // 唤醒等待池中的c2
        }finally{
            lock.unlock(); // 所有的加锁之后的操作都必须使用规定的代码结构来完成
        }
        return number;
    }
    
    public int decrease(){
        lock.lock(); // 对共享变量的操作必须加锁,而且线程通讯必须在拥有的锁的基础上
        try{
            if(number != 1){// 这里没有必要使用循环判断,但是Object.wait必须在循环中判断
                try {
                    c2.await();  // 如果调用c2的方法,那么后面满足条件就应该对应唤醒c2
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            number--;
            c1.signal(); // 唤醒等待池中的c1
        }finally{
            lock.unlock();// 所有的加锁之后的操作都必须使用规定的代码结构来完成
        }
        return number;
    }
    
}


2、Lock 与 synchronized 的比较

1)在JDK 5,Synchronized 要比 Lock 慢很多,但是在 JDK 6 中,它们的效率差不多。

2)Synchronized是Lock的一种简化实现,一个Lock可以对应多个 Condition,而synchronized把Lock和Condition合并了,一个 synchronized Lock只对应一个Condition,可以说Synchronized是Lock 的简化版本。

3)方法对比,使用synchronized的时候都是使用 wait、notify;如果使用Lock,那么需要使用condition的await、singal



3、Lock的一些子类

1)ReentrantLock 一个可重入的互斥锁 Lock,它具有与使用 synchronized 方法和语句所访问的隐式监视器锁相同的一些基本行为和语义,但功能更强大,一般情况下我们只要使用这个对象就可以搞定了!

2)ReentrantReadWriteLock.ReadLock  对于一些只读的操作我们可以赋予它共享锁,也就是读锁,可以多个线程同时读数据,但是不能写数据。lock = new ReentrantReadWriteLock().readLock(); 

3)ReentrantReadWriteLock.WriteLock  对于写操作,那么为了避免脏读,所以我们应该给他加排它锁,这样只能写,不能读,lock = new ReentrantReadWriteLock.WriteLock();





易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!