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

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

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

《深入浅出 Java Concurrency》—锁紧机构(一)Lock与ReentrantLock此处内容已经被作者隐藏,请输入验证码查看内容
验证码:
请关注本站微信公众号,回复“”,获取验证码。在微信里搜索“”或者“”或者微信扫描右侧二维码都可以关注本站微信公众号。

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

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

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

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

  • Idea激活码永久有效Idea2021.3.2激活码教程-持续更新,一步到位

    Idea激活码永久有效Idea2021.3.2激活码教程-持续更新,一步到位Idea激活码永久有效2021.3.2激活码教程-Windows版永久激活-持续更新,Idea激活码2021.3.2成功激活

  • scrapy下载图片报[scrapy.downloadermiddlewares.robotstxt] DEBUG: Forbidden by robots.txt:错误[通俗易懂]

    scrapy下载图片报[scrapy.downloadermiddlewares.robotstxt] DEBUG: Forbidden by robots.txt:错误[通俗易懂]本文转自:http://blog.csdn.net/zzk1995/article/details/51628205先说结论,关闭scrapy自带的ROBOTSTXT_OBEY功能,在setting找到这个变量,设置为False即可解决。使用scrapy爬取淘宝页面的时候,在提交http请求时出现debug信息Forbiddenbyrobots.txt,看来是请求被拒绝了。…

  • 神经网络BP反向传播算法原理和详细推导流程

    神经网络BP反向传播算法原理和详细推导流程1反向传播算法和BP网络简介误差反向传播算法简称反向传播算法(即BP算法)。使用反向传播算法的多层感知器又称为BP神经网络。BP算法是一个迭代算法,它的基本思想为:(1)先计算每一层的状态和激活值,直到最后一层(即信号是前向传播的);(2)计算每一层的误差,误差的计算过程是从最后一层向前推进的(这就是反向传播算法名字的由来);(3)更新参数(目标是误差变小)。迭代前面两个步骤,直到满足…

  • VS2010旗舰版下载

    VS2010旗舰版下载下面这个可用下载:大小2.5Ghttp://download.microsoft.com/download/E/0/4/E0427BB8-8490-4C7F-A05B-AFEA0FC3EA80/X16-60997VS2010UltimTrialCHS.iso//下面没怎么管MicrosoftVisualStudio2010旗舰版(vs2010…

  • 什么是代理服务器(Proxy)

    什么是代理服务器(Proxy)以类似代理人的身份去取得用户所需要的数据就是了!但是由于它的『代理』能力,使得我们可以透过代理服务器来达成防火墙功能与用户浏览数据的分析! 此外,也可以藉由代理服务器来达成节省带宽的目的,以及加快内部网络对因特网的WWW访问速度  17.1.1什么是代理服务器 我们或许会帮忙家人去办理一些杂务吧!举个例子来说,例如缴费或者是申办提款卡等等的,由于你并不是『

  • 代码保护– 几款加壳工具

    代码保护– 几款加壳工具VirboxProtector(商用)分带授权的版本和独立壳。带授权的版本加壳后需要绑定许可,许可控制软件能否用,加壳保护安全。独立版的话就只是对代码做加壳,防止代码反编译。碎片代码执行、外壳加密、混淆、数据加密。服务商提供了较为完善的文档以及加密方式,提供了较为充分的产品管理平台,以及云端网络加密,并且对于开发者免费使用。使用评价:简单下载使用了一下,提供的功能很多,并且管…

发表回复

您的电子邮箱地址不会被公开。

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