《深入浅出 Java Concurrency》—锁紧机构(一)Lock与ReentrantLock

《深入浅出 Java Concurrency》—锁紧机构(一)Lock与ReentrantLock

大家好,又见面了,我是全栈君,今天给大家准备了Idea注册码。

全栈程序员社区此处内容已经被作者隐藏,请输入验证码查看内容
验证码:
请关注本站微信公众号,回复“验证码”,获取验证码。在微信里搜索“全栈程序员社区”或者“www_javaforall_cn”或者微信扫描右侧二维码都可以关注本站微信公众号。

转会: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这是一个明智的选择。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/117878.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • Ubuntu 安装 gcc-4.9.3-64-gnu

    Ubuntu 安装 gcc-4.9.3-64-gnu可能每个人的环境不一样,所以安装的方法有些许差别。我参考了多个网络上的教程,在自己的ubuntu虚拟机中安装了gcc-4.9.3-64-gnu,记录一下自己的安装过程。虚拟机中默认安装了gcc-5.4.0,我要安装gcc-4.9.3一、下载地址:wgethttp://ftp.tsukuba.wide.ad.jp/software/gcc/releases/gcc-4.9.3/gcc-4.9.3.tar.bz2由于是用的虚拟机,配置不是很高,自己是windows下载完毕拷贝进虚拟机中。gcc-gn

    2022年7月24日
    15
  • vs2013下载地址_vs2013使用

    vs2013下载地址_vs2013使用微软已经向MSDN订阅用户提供了VisualStudio2013正式版镜像下载,不过非MSDN用户可以在微软的VisualStudio2013官方网站上下载到正式版镜像(通过下载专业版本,已验证与MSDN版本一致)。下面为大家整理一下个版本下载地址。MicrosoftVisualStudioUltimate2013(简体中文旗舰版)文件名: cn_visual_studio…

    2025年10月25日
    4
  • js读取本地json文件_jquery读取本地json文件

    js读取本地json文件_jquery读取本地json文件1.首先编写一个json文件:demo.json[{“name”:”张三”,”sex”:”男”,”email”:”zhangsan@123.com”},{“name”:”李四”,”sex”:”男”,”email”:”lisi@123.com”},{“name”:”王五”,”sex”:”女”,”email”:”wangwu@123.com…

    2022年10月12日
    3
  • 磁盘在磁盘管理中显示没有初始化找回文件方案「建议收藏」

    磁盘在磁盘管理中显示没有初始化找回文件方案「建议收藏」磁盘没有初始化是因为0号扇区损坏,导致机械硬盘分区表读取不出来,从而机械硬盘出现磁盘没有初始化。工具/软件:极限数据恢复软件步骤1:程序打开后,直接双击需要恢复数据的物理盘。步骤2:等待程序扫描完毕大概需要几分钟到半个小时,稍微耐心等下即可。步骤3:软件扫描到资料后,软件会将扫描到的分区列出来。步骤4:勾上所有需要恢复的资料,右击选择《复制勾选的文件》,…

    2022年9月21日
    2
  • springboot概述_已进入fastboot

    springboot概述_已进入fastbootSpringBoot概述SpringBoot是由Pivotal团队提供的全新框架,其设计目的是用来简化Spring应用的创建、运行、调试、部署等。使用SpringBoot可以做到专注于Spring应用的开发,而无需过多关注XML的配置。SpringBoot使用“习惯优于配置”的理念,简单来说,它提供了一堆依赖打包,并已经按照使用习惯解决了依赖问题。使用SpringBoot可以不用或者只…

    2022年9月2日
    7
  • spdlog 日志库学习,简易封装

    spdlog 日志库学习,简易封装spdlogwiki:https://github.com/gabime/spdlog/wiki别人的学习笔记:https://www.cnblogs.com/oucsheep/p/8426548.html别人的学习笔记:https://github.com/gabime/spdlog/wiki百度搜spdlog封装可以看到很多写的差不多的单例类,我看公司遗留的代码也是借鉴这些写的。最常见的是一开头就写上:#ifdef_WIN32#define__FILENAME__(s

    2022年6月23日
    59

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号