《深入浅出 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)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • python中%d_python中%d是什么「建议收藏」

    python中%d表示格式化一个对象为十进制整数。使用后,在需要输出的长字符串中占位置。输出字符串时,可以依据变量的值,自动更新字符串的内容。使用示例:num=14#%d打印时结果是14print(“num=%d”%num)#output:num=14#%1d意思是打印结果为1位整数,当整数的位数超过1位时,按整数原值打印,所以%1d的打印结果还是14print(“nu…

    2022年4月10日
  • ip2long之后有什么好处?

    ip2long之后有什么好处?

    2021年10月18日
  • springboot集成dubbo的配置(dubbo项目如何部署)

    1.Dubbo框架Dubbo框架是一个高性能、重量轻、基于java的RPC框架。Dubbo提供了三个关键功能,包括基于接口的远程调用、容错和负载平衡,以及自动服务注册和发现。Dubbo可以和Spring框架无缝集成。官方的Dubbo框架如下图所示:其核心部分包含:1.远程通讯:提供对多种基于长连接的NIO框架抽象封装,包括多种线程模型,序列化,以及“请求-响应”模式的信息交换方式。2.集群容错:提供基于接口方法的透明远程过程调用,包括多协议支持,以及软负载均衡…

    2022年4月16日
  • c语言病毒源码讲解,【病毒】震荡波病毒C语言源码「建议收藏」

    该楼层疑似违规已被系统折叠隐藏此楼查看此楼/*#include#include#include#include#include#defineNORM”\033[00;00m”#defineGREEN”\033[01;32m”#defineYELL”\033[01;33m”#defineRED”\033[01;31m”#defineBANNERGREEN”…

    2022年4月14日
  • 阅读书源最新2020在线导入_最最最最最好用的小说神器,全网书源免费用!

    阅读书源最新2020在线导入_最最最最最好用的小说神器,全网书源免费用!今天给大家分享的是小说软件,为了满足所有小伙伴的需求,今天安卓和苹果都安排上了,一款Android应用,一款iOS应用。两款应用都十分相似,都是可以自行添加书源的软件,几乎覆盖全网小说。阅读(Android)软件本身是没有任何资源的,如果不添加书源地址,也不能搜索到任何小说。书源添加流程:软件想要很好的使用,还需要添加书源,该软件自己有一个在线书源库,内含上千个书源地址,足够满足大家的使…

    2022年6月17日
  • ActiveMQ入门系列一:认识并安装ActiveMQ(Windows下)

    一、什么是ActiveMQ度娘给出的定义:ActiveMQ的官网打出的标语(如上图):大意是:兼容性好并且功能强大的开源多协议消息中间件,那具体是怎么体现的呢?1.兼容性好:ActiveMQ可以

    2022年2月16日

发表回复

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

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