转会:http://www.blogjava.net/xylz/archive/2010/07/05/325274.html

前面的章节主要谈谈原子操作,至于与原子操作一些相关的问题或者说陷阱就放到最后的总结篇来总体说明。

从这一章開始花少量的篇幅谈谈锁机制。

上一个章节 中谈到了锁机制,而且针对于原子操作谈了一些相关的概念和设计思想。接下来的文章中。尽可能的深入研究锁机制,而且理解里面的原理和实际应用场合。

虽然synchronized在语法上已经足够简单了。在JDK 5之前仅仅能借助此实现,可是因为是独占锁。性能却不高,因此JDK 5以后就開始借助于JNI来完毕更高级的锁实现。

JDK 5中的锁是接口java.util.concurrent.locks.Lock 。

另外java.util.concurrent.locks.ReadWriteLock 提供了一对可供读写并发的锁。依据前面的规则,我们从java.util.concurrent.locks.Lock 的API開始。

void lock();

获取锁。

假设锁不可用。出于线程调度目的,将禁用当前线程。而且在获得锁之前。该线程将一直处于休眠状态。

void lockInterruptibly() throws InterruptedException;

假设当前线程未被中断。则获取锁。

假设锁可用。则获取锁,并马上返回。

假设锁不可用,出于线程调度目的,将禁用当前线程,而且在发生下面两种情况之中的一个曾经。该线程将一直处于休眠状态:

  • 锁由当前线程获得;或者
  • 其它某个线程中断 当前线程,而且支持对锁获取的中断。

假设当前线程:

  • 在进入此方法时已经设置了该线程的中断状态;或者
  • 在获取锁时被中断 ,而且支持对锁获取的中断,

则将抛出  InterruptedException 。并清除当前线程的已中断状态。

Condition newCondition();

返回绑定到此  Lock   实例的新  Condition   实例。下一小节中会重点谈Condition,此处不做过多的介绍。

boolean tryLock();

仅在调用时锁为空暇状态才获取该锁。

假设锁可用,则获取锁,并马上返回值  true 。假设锁不可用。则此方法将马上返回值  false 。

通常对于那些不是必须获取锁的操作可能实用。

boolean tryLock(long time, TimeUnit unit) throws InterruptedException;

假设锁在给定的等待时间内空暇,而且当前线程未被中断,则获取锁。

假设锁可用,则此方法将马上返回值  true 。假设锁不可用,出于线程调度目的,将禁用当前线程,而且在发生下面三种情况之中的一个前,该线程将一直处于休眠状态:

  • 锁由当前线程获得;或者
  • 其它某个线程中断当前线程,而且支持对锁获取的中断;或者
  • 已超过指定的等待时间

假设获得了锁,则返回值  true 。

假设当前线程:

  • 在进入此方法时已经设置了该线程的中断状态;或者
  • 在获取锁时被中断,而且支持对锁获取的中断。

则将抛出  InterruptedException 。并会清除当前线程的已中断状态。

假设超过了指定的等待时间。则将返回值  false 。假设 time 小于等于 0,该方法将全然不等待。

void unlock();

释放锁。

相应于lock()、tryLock()、tryLock(xx)、lockInterruptibly()等操作,假设成功的话应该相应着一个unlock(),这样能够避免死锁或者资源浪费。

相对于比較空洞的API。来看一个实际的样例。以下的代码实现了一个类似于AtomicInteger的操作。

package xylz.study.concurrency.lock;

import java.util.concurrent.locks.Lock;

import java.util.concurrent.locks.ReentrantLock;

public class AtomicIntegerWithLock {

private int value;

private Lock lock = new ReentrantLock();

public AtomicIntegerWithLock() {

        super();

    }

public AtomicIntegerWithLock(int value) {

        this.value = value;

    }

public final int get() {

        lock.lock();

        try {

            return value;

        } finally {

            lock.unlock();

        }

    }

public final void set(int newValue) {

        lock.lock();

        try {

            value = newValue;

        } finally {

            lock.unlock();

        }

}

public final int getAndSet(int newValue) {

        lock.lock();

        try {

            int ret = value;

            value = newValue;

            return ret;

        } finally {

            lock.unlock();

        }

    }

public final boolean compareAndSet(int expect, int update) {

        lock.lock();

        try {

            if (value == expect) {

                value = update;

                return true;

            }

            return false;

        } finally {

            lock.unlock();

        }

    }

public final int getAndIncrement() {

        lock.lock();

        try {

            return value++;

        } finally {

            lock.unlock();

        }

    }

public final int getAndDecrement() {

        lock.lock();

        try {

            return value--;

        } finally {

            lock.unlock();

        }

    }

public final int incrementAndGet() {

        lock.lock();

        try {

            return ++value;

        } finally {

            lock.unlock();

        }

    }

public final int decrementAndGet() {

        lock.lock();

        try {

            return --value;

        } finally {

            lock.unlock();

        }

    }

public String toString() {

        return Integer.toString(get());

    }

}

AtomicIntegerWithLock 是线程安全的,此结构中大量使用了Lock对象的lock/unlock方法对。相同可以看到的是对于自增和自减操作使用了++/--。之所以可以保证线程安全,是由于Lock对象的lock()方法保证了仅仅有一个线程可以仅仅有此锁。须要说明的是对于不论什么一个lock()方法,都须要一个unlock()方法与之对于,通常情况下为了保证unlock方法总是可以得到运行,unlock方法被置于finally块中。另外这里使用了java.util.concurrent.locks.ReentrantLock.ReentrantLock 对象。下一个小节中会详细描写叙述此类作为Lock的唯一实现是怎样设计和实现的。

虽然synchronized实现Lock的同样语义,而且在语法上比Lock要简单多。可是前者却比后者的开销要大得多。做一个简单的測试。

public static void main(String[] args) throws Exception{

     final int max = 10;

     final int loopCount = 100000;

     long costTime = 0;

     for (int m = 0; m < max; m++) {

         long start1 = System.nanoTime();

         final AtomicIntegerWithLock value1 = new AtomicIntegerWithLock(0);

         Thread[] ts = new Thread[max];

         for(int i=0;i<max;i++) {

             ts[i] = new Thread() {

                 public void run() {

                     for (int i = 0; i < loopCount; i++) {

                         value1.incrementAndGet();

                     }

                 }

             };

         }

         for(Thread t:ts) {

             t.start();

         }

         for(Thread t:ts) {

             t.join();

         }

         long end1 = System.nanoTime();

         costTime += (end1-start1);

     }

     System.out.println("cost1: " + (costTime));

     //

     System.out.println();

     costTime = 0;

     //

     final Object lock = new Object();

     for (int m = 0; m < max; m++) {

         staticValue=0;

         long start1 = System.nanoTime();

         Thread[] ts = new Thread[max];

         for(int i=0;i<max;i++) {

             ts[i] = new Thread() {

                 public void run() {

                     for (int i = 0; i < loopCount; i++) {

                         synchronized(lock) {

                             ++staticValue;

                         }

                     }

                 }

             };

         }

         for(Thread t:ts) {

             t.start();

         }

         for(Thread t:ts) {

             t.join();

         }

         long end1 = System.nanoTime();

         costTime += (end1-start1);

     }

     //

     System.out.println("cost2: " + (costTime));

}

static int staticValue = 0;

在这个样例中每次启动10个线程,每一个线程计算100000次自增操作,反复測试10次,以下是某此測试的结果:

cost1: 624071136

cost2: 2057847833

虽然上面的例子是不是很正规的测试案例,然而,上述例子是为了说明,Lock性能比synchronized更好。那么假设可以随时使用Lock替代synchronized这是一个明智的选择。

《深入浅出 Java Concurrency》—锁紧机构(一)Lock与ReentrantLock的更多相关文章

  1. 深入浅出 Java Concurrency (8): 加锁的原理 (Lock.lock)

    接上篇,这篇从Lock.lock/unlock开始.特别说明在没有特殊情况下所有程序.API.文档都是基于JDK 6.0的. public void java.util.concurrent.lock ...

  2. 深入浅出 Java Concurrency 锁机制 : AQS

    转载:http://www.blogjava.net/xylz/archive/2010/07/06/325390.html 在理解J.U.C原理以及锁机制之前,我们来介绍J.U.C框架最核心也是最复 ...

  3. [转] 多线程 《深入浅出 Java Concurrency》目录

    http://ifeve.com/java-concurrency-thread-directory/ synchronized使用的内置锁和ReentrantLock这种显式锁在java6以后性能没 ...

  4. 《深入浅出 Java Concurrency》目录

    最近在学习J.U.C,看到一个大神 关于这个系列写的非常精辟,由于想做笔记,故系列转载并记录之. 原文:http://www.blogjava.net/xylz/archive/2010/07/08/ ...

  5. 深入浅出 Java Concurrency - 目录 [转]

    这是一份完整的Java 并发整理笔记,记录了我最近几年学习Java并发的一些心得和体会. J.U.C 整体认识 原子操作 part 1 从AtomicInteger开始 原子操作 part 2 数组. ...

  6. 深入浅出 Java Concurrency (6): 锁机制 part 1 Lock与ReentrantLock

      前面的章节主要谈谈原子操作,至于与原子操作一些相关的问题或者说陷阱就放到最后的总结篇来整体说明.从这一章开始花少量的篇幅谈谈锁机制. 上一个章节中谈到了锁机制,并且针对于原子操作谈了一些相关的概念 ...

  7. 深入浅出 Java Concurrency (9): 锁机制 part 4 锁释放与条件变量 (Lock.unlock And Condition)

    本小节介绍锁释放Lock.unlock(). Release/TryRelease unlock操作实际上就调用了AQS的release操作,释放持有的锁. public final boolean ...

  8. 深入浅出 Java Concurrency (15): 锁机制 part 10 锁的一些其它问题

      主要谈谈锁的性能以及其它一些理论知识,内容主要的出处是<Java Concurrency in Practice>,结合自己的理解和实际应用对锁机制进行一个小小的总结. 首先需要强调的 ...

  9. 深入浅出 Java Concurrency (12): 锁机制 part 7 信号量(Semaphore)

      Semaphore 是一个计数信号量.从概念上讲,信号量维护了一个许可集.如有必要,在许可可用前会阻塞每一个 acquire(),然后再获取该许可.每个 release() 添加一个许可,从而可能 ...

随机推荐

  1. MapReduce调度与执行原理之作业初始化

    前言 :本文旨在理清在Hadoop中一个MapReduce作业(Job)在提交到框架后的整个生命周期过程,权作总结和日后参考,如有问题,请不吝赐教.本文不涉及Hadoop的架构设计,如有兴趣请参考相关 ...

  2. jquery实现鼠标焦点十字效果

    系统开发时很多地方需要有焦点效果,例如:鼠标点击聚焦,地图定位,在图片上突出显示,焦点定位页面元素. 本小功能通过jquery和graphics二次开发,实现通过鼠标点击页面任何区域,聚焦当前点击位置 ...

  3. UVA11324-- The Largest Clique(SCC+DP)

    题目链接 题意:给出一张有向图,求一个结点数最大的结点集,使得该结点集中随意两个结点u和v满足:要么u能够到到v,要么v能够到达u(u和v能够互相到达) 思路:我们能够缩点,用Tarjan求出全部强连 ...

  4. Swift - 协议(protocol)

    1,Swift中协议类似于别的语言里的接口,协议里只做方法的声明,包括方法名.返回值.参数等信息,而没有具体的方法实现. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 ...

  5. 用Python制作游戏外挂(上)

    源地址:http://eyehere.net/2012/python-game-bot-autopy-1/ 悲剧成我这样的人,我知道肯定不止我一个,所以我一点都不悲伤:-( 所以我打开了4399小游戏 ...

  6. ThinkPhp学习11

    原文:ThinkPhp学习11 一.模板的使用        (重点) a.规则 模板文件夹下[TPL]/[分组文件夹/][模板主题文件夹/]和模块名同名的文件夹[Index]/和方法名同名的文件[i ...

  7. java基础---->java调用oracle存储过程(转)

    存储过程是在大型数据库系统中,一组为了完成特定功能的SQL 语句集,存储在数据库中,经过第一次编译后再次调用不需要再次编译,用户通过指定存储过程的名字并给出参数(如果该存储过程带有参数)来执行它.今天 ...

  8. windows程序员进阶系列:《软件调试》之Win32堆的调试支持

    Win32堆的调试支持 为了帮助程序员及时发现堆中的问题,堆管理器提供了以下功能来辅助调试. 1:堆尾检查(Heap Tail Check) HTC,在堆尾添加额外的标记信息,用于检测堆块是否溢出. ...

  9. OCP读书笔记(1) - Oracle核心概念和工具

    ohasdoracle high available service daemon OEMweb -- Database Control资料库 -- sysman Starting Oracle Re ...

  10. 事务应用-运行多条SQL语句

    事务具有原子性,要么不运行,要么全运行,一旦成功运行永久保存.而这些正是因为事务的原子性和对数据库的持久性形成的.下面是一个关于统一给数据库中的数据改动的批量操作,利用到事务. TODO:批量改动数据 ...