zoukankan      html  css  js  c++  java
  • 12、java5锁java.util.concurrent.locks.Lock之ReentrantLock

    JDK文档描述:

    public interface LockLock 
    实现提供了比使用 synchronized 方法和语句可获得的更广泛的锁定操作。此实现允许更灵活的结构,可以具有差别很大的属性,可以支持多个相关的 Condition 对象。 
    
    锁是控制多个线程对共享资源进行访问的工具。通常,锁提供了对共享资源的独占访问。一次只能有一个线程获得锁,对共享资源的所有访问都需要首先获得锁。不过,某些锁可能允许对共享资源并发访问,如 ReadWriteLock 的读取锁。 
    
    synchronized 方法或语句的使用提供了对与每个对象相关的隐式监视器锁的访问,但却强制所有锁获取和释放均要出现在一个块结构中:当获取了多个锁时,它们必须以相反的顺序释放,且必须在与所有锁被获取时相同的词法范围内释放所有锁。 
    
    虽然 synchronized 方法和语句的范围机制使得使用监视器锁编程方便了很多,而且还帮助避免了很多涉及到锁的常见编程错误,但有时也需要以更为灵活的方式使用锁。例如,某些遍历并发访问的数据结果的算法要求使用 "hand-over-hand" 或 "chain locking":获取节点 A 的锁,然后再获取节点 B 的锁,然后释放 A 并获取 C,然后释放 B 并获取 D,依此类推。Lock 接口的实现允许锁在不同的作用范围内获取和释放,并允许以任何顺序获取和释放多个锁,从而支持使用这种技术。 
    
    随着灵活性的增加,也带来了更多的责任。不使用块结构锁就失去了使用 synchronized 方法和语句时会出现的锁自动释放功能。在大多数情况下,应该使用以下语句: 
    
         Lock l = ...; 
         l.lock();
         try {
             // access the resource protected by this lock
         } finally {
             l.unlock();
         }
     锁定和取消锁定出现在不同作用范围中时,必须谨慎地确保保持锁定时所执行的所有代码用 try-finallytry-catch 加以保护,以确保在必要时释放锁。 
    Lock 实现提供了使用 synchronized 方法和语句所没有的其他功能,包括提供了一个非块结构的获取锁尝试 (tryLock())、一个获取可中断锁的尝试 (lockInterruptibly()) 和一个获取超时失效锁的尝试 (tryLock(long, TimeUnit))。 
    
    Lock 类还可以提供与隐式监视器锁完全不同的行为和语义,如保证排序、非重入用法或死锁检测。如果某个实现提供了这样特殊的语义,则该实现必须对这些语义加以记录。 
    
    注意,Lock 实例只是普通的对象,其本身可以在 synchronized 语句中作为目标使用。获取 Lock 实例的监视器锁与调用该实例的任何 lock() 方法没有特别的关系。为了避免混淆,建议除了在其自身的实现中之外,决不要以这种方式使用 Lock 实例。 
    
    除非另有说明,否则为任何参数传递 null 值都将导致抛出 NullPointerException。 

    子类:

    所有已知实现类: 
    ReentrantLock, 
    ReentrantReadWriteLock.ReadLock, ReentrantReadWriteLock.WriteLock 

     ReentrantLock的方法:

    方法摘要
     int getHoldCount()
              查询当前线程保持此锁的次数。
    protected  Thread getOwner()
              返回目前拥有此锁的线程,如果此锁不被任何线程拥有,则返回 null
    protected  Collection<Thread> getQueuedThreads()
              返回一个 collection,它包含可能正等待获取此锁的线程。
     int getQueueLength()
              返回正等待获取此锁的线程估计数。
    protected  Collection<Thread> getWaitingThreads(Condition condition)
              返回一个 collection,它包含可能正在等待与此锁相关给定条件的那些线程。
     int getWaitQueueLength(Condition condition)
              返回等待与此锁相关的给定条件的线程估计数。
     boolean hasQueuedThread(Thread thread)
              查询给定线程是否正在等待获取此锁。
     boolean hasQueuedThreads()
              查询是否有些线程正在等待获取此锁。
     boolean hasWaiters(Condition condition)
              查询是否有些线程正在等待与此锁有关的给定条件。
     boolean isFair()
              如果此锁的公平设置为 true,则返回 true
     boolean isHeldByCurrentThread()
              查询当前线程是否保持此锁。
     boolean isLocked()
              查询此锁是否由任意线程保持。
     void lock()
              获取锁。
     void lockInterruptibly()
              如果当前线程未被中断,则获取锁。
     Condition newCondition()
              返回用来与此 Lock 实例一起使用的 Condition 实例。
     String toString()
              返回标识此锁及其锁定状态的字符串。
     boolean tryLock()
              仅在调用时锁未被另一个线程保持的情况下,才获取该锁。
     boolean tryLock(long timeout, TimeUnit unit)
              如果锁在给定等待时间内没有被另一个线程保持,且当前线程未被中断,则获取该锁。
     void unlock()
              试图释放此锁。

    下面我用ReentrantLock来改写http://www.cnblogs.com/yangzhilong/p/4752480.html 中的部分代码

    package com.yzl;
    
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    public class ThreadPart_lock {
        public static void main(String[] args) {
            testLock();
        }
            
        /**
         * 使用同一个对象的同一个lock
         * 此时用Lock代替了synchronized所指向的锁对象,
         * 故是否是同一个Work对象不重要了,是同一个Lock就行,可以在外面new同一个锁然后传入write方法达到同样的效果
         * 
         */
        private static void testLock(){
            final Work work = new ThreadPart_lock.Work();
            
            Thread thread = new Thread(new Runnable() {
                @Override
                public void run() {
                    while(true){
                        work.write("wangwu");
                    }
                }
            });
            thread.start();
            
            Thread thread1 = new Thread(new Runnable() {
                @Override
                public void run() {
                    while(true){
                        work.write("zhangsan");
                    }
                }
            });
            thread1.start();
        }
        
        static class Work {
            Lock lock = new ReentrantLock();
            
            public void write(String name){
                //synchronized (this) {
                lock.lock();
                
                try{
                    for(int i=0; i<name.length(); i++){
                        System.out.print(name.charAt(i));
                        if(i == (name.length()-1)){
                            System.out.print("
    ");
                        }
                    }
                }finally{
                    //为防止出现出现异常后锁没释放
                    lock.unlock();
                }
                //}
            }
        }
    }
  • 相关阅读:
    [导入]Repeater与DataGrid的效率,到底哪个的更好?!(结论很可能和你认为的不一样!)
    开发工具的选择
    在WINDOWS 下删除EISA配置的隐藏分区
    DNN使用升级包升级
    DNN中代码创建用户的CreateUser()方法的疑问
    eWebEditor的数据库连接字符串
    c/c++笔试题目(林锐)
    如何下载网页中的flash文件
    DotNetNuke: System.Security.Cryptography.CryptographicException: Bad Data
    win7安装iis错误解决方法汇总
  • 原文地址:https://www.cnblogs.com/yangzhilong/p/4799343.html
Copyright © 2011-2022 走看看