java并发编程--互斥锁, 读写锁及条件

java.util.concurrent.locks包提供了锁和等待条件的接口和类, 可用于替代JDK1.5以前的同步(synchronized)和监视器机制(主要是Object类的wait(), notify(), notifyAll()方法).java

 

互斥锁--Lock接口及其实现类ReentrantLock并发

所谓互斥锁, 指的是一次最多只能有一个线程持有的锁. 在jdk1.5以前, 咱们一般使用synchronized机制控制多个线程对共享资源的访问. 而如今, Lock提供了比synchronized机制更普遍的锁定操做, Lock和synchronized机制的主要区别:高并发

  • synchronized机制提供了对与每一个对象相关的隐式监视器锁的访问, 并强制全部锁获取和释放均要出如今一个块结构中, 当获取了多个锁时, 它们必须以相反的顺序释放. synchronized机制对锁的释放是隐式的, 只要线程运行的代码超出了synchronized语句块范围, 锁就会被释放. 而Lock机制必须显式的调用Lock对象的unlock()方法才能释放锁, 这为获取锁和释放锁不出如今同一个块结构中, 以及以更自由的顺序释放锁提供了可能. 如下代码演示了在不一样的块结构中获取和释放锁:

Java代码 性能

  1. public class LockTest {  
        private static Lock lock = new ReentrantLock();  
        public static void main(String[] args) {  
            lock.lock();  
            invokeMethod();  
        }  
      
        private static void invokeMethod() {  
            lock.unlock();  
        }  
    }  

     

  为了确保锁被释放, 一般会采用以下的代码形式:this

Java代码 线程

  1. Lock lock = new ReentrantLock();  
    // 获取锁  
    lock.lock();  
        try {  
            // access the resource protected by this lock  
        } finally {  
            // 释放锁  
            lock.unlock();  
        }  

     

  |--void lock(): 执行此方法时, 若是锁处于空闲状态, 当前线程将获取到锁. 相反, 若是锁已经被其余线程持有, 将禁用当前线程, 直到当前线程获取到锁.code

|--void unlock(): 执行此方法时, 当前线程将释放持有的锁. 锁只能由持有者释放, 若是线程并不持有锁, 却执行该方法, 可能致使异常的发生.orm

  • Lock提供了一个非块结构的获取锁尝试--tryLock(), 一个获取可中断锁的尝试--lockInterruptibly()和一个获取超时失效锁的尝试--tryLock(long time, TimeUnit unit).

|--boolean tryLock(): 若是锁可用, 则获取锁, 并当即返回true, 不然返回false. 该方法和lock()的区别在于, tryLock()只是"试图"获取锁, 若是锁不可用, 不会致使当前线程被禁用, 当前线程仍然继续往下执行代码. 而lock()方法则是必定要获取到锁, 若是锁不可用, 就一直等待, 在未得到锁以前,当前线程并不继续向下执行. 一般采用以下的代码形式调用tryLock()方法:对象

 

Java代码 blog

  1. Lock lock = new ReentrantLock();  
       if (lock.tryLock()) {  
           try {  
               // manipulate protected state  
           } finally {  
               lock.unlock();  
           }  
       } else {  
           // perform alternative actions  
       }  

     

此用法可确保若是获取了锁, 则会释放锁; 若是未获取锁, 则不会试图将其释放.

  • Lock的newCondition()方法能够得到与该锁绑定的Condition对象, Condition的详细介绍以下. 

 

条件--Condition

调用Condition对象的相关方法, 能够方便的挂起和唤醒线程. Object对象的wait(), notify(), notifyAll()方法固然也能够作到这一点, 可是Object对象的这些方法存在很不方便的地方--若是多个线程调用了obj的wait()方法而挂起, 那么咱们没法作到调用obj的notify()和notifyAll()方法唤醒其中特定的一个线程. 而Condition对象就能够作到这一点. 具体的代码请参见个人上一篇博客http://coolxing.iteye.com/blog/1236696中的解法二部分.

  • void await(): 调用Condition对象的await()方法将致使当前线程被挂起, 并释放该Condition对象所绑定的锁. Condition对象只能经过Lock类的newCondition()方法获取, 所以一个Condition对象必然有一个与其绑定的Lock锁. 调用Condition对象的await()方法的前提是: 当前线程必须持有与该Condition对象绑定的锁, 不然程序可能抛出异常.
  • void signal(): 唤醒一个在该Condition对象上挂起的线程. 若是存在多个线程等待这个Condition对象的唤醒, 则随机选择一个. 线程被唤醒以前, 必须从新获取到锁(与该Condition对象绑定的Lock对象).
  • void signalAll(): 唤醒全部在该Condition对象上挂起的线程. 全部被唤醒的线程将竞争与该Condition对象绑定的锁, 只有获取到锁的线程才能恢复到运行状态.

 

读写锁--ReadWriteLock接口及其实现类ReentrantReadWriteLock

ReentrantReadWriteLock中定义了2个内部类, ReentrantReadWriteLock.ReadLock和ReentrantReadWriteLock.WriteLock, 分别用来表明读取锁和写入锁. ReentrantReadWriteLock对象提供了readLock()和writeLock()方法, 用于获取读取锁和写入锁. 

 

  • 读取锁容许多个reader线程同时持有, 而写入锁最多只能有一个writter线程持有.
  • 读写锁的使用场合: 读取共享数据的频率远大于修改共享数据的频率. 在上述场合下, 使用读写锁控制共享资源的访问, 能够提升并发性能.
  • 若是一个线程已经持有了写入锁, 则能够再持有读写锁. 相反, 若是一个线程已经持有了读取锁, 则在释放该读取锁以前, 不能再持有写入锁.
  • 能够调用写入锁的newCondition()方法获取与该写入锁绑定的Condition对象, 此时与普通的互斥锁并无什么区别. 可是调用读取锁的newCondition()方法将抛出异常. 

使用读写锁的一个例子:


Java代码 

public class ReadWriteLockTest {  
    private static ReadWriteLock lock = new ReentrantReadWriteLock();  
    private static Person person = new Person("David Beckham", true);  
  
    public static void main(String[] args) {  
        new Thread() {  
            public void run() {  
                while(true) {  
                    try {  
                        lock.readLock().lock();  
                        System.out.print("name = " + person.getName());  
                        System.out.println(", isMan = " + person.isMan());  
                    } finally {  
                        lock.readLock().unlock();  
                    }  
                }  
            };  
        }.start();  
        new Thread() {  
            public void run() {  
                boolean state = true;  
                while(true) {  
                    try {  
                        lock.writeLock().lock();  
                        if (state) {  
                            person.setName("Lady GaGa");  
                            person.setMan(false);  
                            state = false;  
                        } else {  
                            person.setName("David Beckham");  
                            person.setMan(true);  
                            state = true;  
                        }  
                          
                    } finally {  
                        lock.writeLock().unlock();  
                    }  
                }  
            };  
        }.start();  
    }  
}  
  
class Person {  
    private String name;  
    private boolean isMan;  
  
    public Person(String name, boolean isMan) {  
        this.name = name;  
        this.isMan = isMan;  
    }  
  
    public String getName() {  
        return name;  
    }  
  
    public void setName(String name) {  
        this.name = name;  
    }  
  
    public boolean isMan() {  
        return isMan;  
    }  
  
    public void setMan(boolean isMan) {  
        this.isMan = isMan;  
    }  
}  

无论程序运行多久, 也不会有人妖的出现.

相关文章
相关标签/搜索