专栏首页杂烩java多线程加锁的简单处理办法 原

java多线程加锁的简单处理办法 原

    当对数据修改时,如果两个线程同时去修改同一条数据,这样产生的结果就不是我们预期的结果。这时候就需要对修改操作进行加锁,让jvm里同一时刻只能有一个线程能够执行修改方法。

    下面是一个未加锁的修改方法:   

public void update(Entry entry){
    dao.update(entry);
}

    现在讨论下传统的加锁方法。我们知道每一个对象都隐含了一个锁,那就是对象本身。我们可以在方法体上加上同步字段synchronized

public synchronized void update(Entry entry){
    dao.update(entry);
}

但如果方法里代码很多,那么加在方法上会锁住很多代码,我们可以使用同步块

public void update(Entry entry){
    dobefore();
    synchronized(this){
        dao.update(entry);
    }
    doend(); 
}

    而需要注意的是如果一个类中存在多个同步方法,那么所有同步方法的锁都是对象本身,也就是说当执行update的时候,别的线程不仅不能执行update连类中别的同步方法也不能使用。当然也可以使用一点技巧去规避这个问题,比如使用其他锁。

    我们这篇博客说得不是上面的方法,而是另外一个位于java.util.concurrent.locks包下的ReentrantLock。

    官方是这么说的:

    一个可重入的互斥锁 Lock,它具有与使用 synchronized 方法和语句所访问的隐式监视器锁相同的一些基本行为和语义,但功能更强大。     ReentrantLock 将由最近成功获得锁,并且还没有释放该锁的线程所拥有。当锁没有被另一个线程所拥有时,调用 lock 的线程将成功获取该锁并返回。如果当前线程已经拥有该锁,此方法将立即返回。可以使用 isHeldByCurrentThread() 和 getHoldCount() 方法来检查此情况是否发生。     此类的构造方法接受一个可选的公平 参数。当设置为 true 时,在多个线程的争用下,这些锁倾向于将访问权授予等待时间最长的线程。否则此锁将无法保证任何特定访问顺序。与采用默认设置(使用不公平锁)相比,使用公平锁的程序在许多线程访问时表现为很低的总体吞吐量(即速度很慢,常常极其慢),但是在获得锁和保证锁分配的均衡性时差异较小。不过要注意的是,公平锁不能保证线程调度的公平性。因此,使用公平锁的众多线程中的一员可能获得多倍的成功机会,这种情况发生在其他活动线程没有被处理并且目前并未持有锁时。还要注意的是,未定时的 tryLock 方法并没有使用公平设置。因为即使其他线程正在等待,只要该锁是可用的,此方法就可以获得成功。

    使用它也很简单,你可以用如下结构来使用他:   

class X {
   private final ReentrantLock lock = new ReentrantLock();
   // ...

   public void m() { 
     lock.lock();  // block until condition holds
     try {
       // ... method body
     } finally {
       lock.unlock()
     }
   }
 }

    常用的方法就如上面所说的一样,lock和unlock   

lock
public void lock()
获取锁。
如果该锁没有被另一个线程保持,则获取该锁并立即返回,将锁的保持计数设置为 1。
如果当前线程已经保持该锁,则将保持计数加 1,并且该方法立即返回。
如果该锁被另一个线程保持,则出于线程调度的目的,禁用当前线程,并且在获得锁之前,该线程将一直处于休眠状态,此时锁保持计数被设置为 1。
指定者:
接口 Lock 中的 
lock

unlock
public void unlock()
试图释放此锁。
如果当前线程是此锁所有者,则将保持计数减 1。如果保持计数现在为 0,则释放该锁。如果当前线程不是此锁的持有者,则抛出 IllegalMonitorStateException。
指定者:
接口 Lock 中的 
unlock
抛出:
IllegalMonitorStateException - 如果当前线程没有保持此锁

    当然他还有别的很多方法,需要的话可以自己去看看。

    对比synchronized这个锁是独立的,在一个类中多个同步块之间都是独立的,互不影响。最后说一句,因为同步块会让一段代码同一时刻只能有一个线程使用,多线程同时访问,一个使用其他都是等待状态,那么就存在一个性能问题。如果理解原子性,又那么牛X,利用原子性写出避免同步的免锁代码,什么synchronized啊,ReentrantLock啊,都是浮云。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Java-ThreadPoolExecutor类

            handler:提交线程数量大于maximumPoolSize时的处理器

    尚浩宇
  • kafka报org.apache.kafka.common.errors.RecordTooLargeException

    可以看到默认是1M,只需要在配置kafka连接时,加入配置max.request.size即可,如下:

    尚浩宇
  • Docker容器之最小JDK基础镜像 原

        2、因为java依赖glibc,所以基础镜像使用的是alpine-glibc而非alpine,alpine-glibc大概是11.1M。

    尚浩宇
  • Java 中的锁原理、锁优化、CAS、AQS 详解!

    结论:如果volatile变量修饰符使用恰当的话,它比synchronized的使用和执行成本更低,因为它不会引起线程上下文的切换和调度。

    Java团长
  • Java 中的锁原理、锁优化、CAS、AQS 详解!

    结论:如果volatile变量修饰符使用恰当的话,它比synchronized的使用和执行成本更低,因为它不会引起线程上下文的切换和调度。

    芋道源码
  • 你必须要知道的锁原理、锁优化、CAS、AQS

    出处:https://www.jianshu.com/p/e674ee68fd3f

    好好学java
  • .Net线程同步技术解读

    如果代码在多线程环境中运行的结果与单线程运行结果一样,其他变量值也和预期是一样的,那么线程就是安全的;

    心莱科技雪雁
  • Java Concurrent synchronized 使用&原理

    sychronized 是Java语法层面的同步策略,可以用来修饰instance变量、object reference(对象引用)、static函数和clas...

    邹志全
  • [nptl][mutex]老司机带你十分钟定位死锁问题

    前言: 死锁问题,几乎可以用“自古”来形容。PV原语一出,信号量嵌套使用,就伴随着死锁问题的发生。死锁类问题的解决过程,基本上就是定位到发生死锁的位置以及原因,...

    皮振伟
  • Java中的锁原理、锁优化、CAS、AQS

    结论:如果volatile变量修饰符使用恰当的话,它比synchronized的使用和执行成本更低,因为它不会引起线程上下文的切换和调度。

    Java团长

扫码关注云+社区

领取腾讯云代金券