Java线程安全解决方案(synchronized,ReentrantLock,Atomic)

 更新时间:2020年09月27日 14:23:29   作者:雨developer  
这篇文章主要介绍了Java线程安全解决方案(synchronized,ReentrantLock,Atomic),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

线程安全解决方案

synchronized,ReentrantLock,Atomic 使用场景描述

在实际开发过程中如果服务量,请求频繁,就会经常碰见并发,这时候不做处理就会出现很多非法数据。这时候就需要解决线程安全的问题,这时候就可以使用java当中的锁机制。常用有java关键synchronized、可重入锁ReentrantLock,还有并发包下的Atomic 或者Concurrent的安全类型。

synchronized使用场景:

在资源竞争不是很激烈的情况下,偶尔出现并发,需要同步的情形下,synchronized是很合适的。原因在于,编译程序通常会尽可能的进行优化synchronized,另外可读性非常好,不管用没用过5.0多线程包的程序员都能理解。可以多对方法进行加锁(同步方法),也可以对对象进行加锁(同步代码快)。

  /**
   * synchronized用id
   */
  private static volatile Long syncId=0L;

  /**
   * synchronized方式获取id 同步方法
   * @return
   */
  public static synchronized Long getSyncId1(){
    syncId++;
    return syncId;
  }

  /**
   * synchronized方式获取id 同步代码块
   * @return
   */
  public static Long getSyncId2(){
    synchronized (syncId){
      syncId++;
      return syncId;
    }
  }

代码可读性强,毕竟是java的关键字,执行优先级高。synchronized关键字一放,就解决线程安全的问题。

但是还有一个问题,当前资源竞争激烈时,对于部分线程迟迟获取不到锁,这时候会出现一个锁升级的过程,且锁升级的过程是不可逆的。当从轻量级锁到偏向锁,再到一个重量级锁。性能会大大的降低。

在资源竞争激烈可以使用其他方式来加锁。

ReentrantLock使用场景:

ReentrantLock提供了多样化的同步,比如有时间限制的同步,可以被Interrupt的同步(synchronized的同步是不能Interrupt的)等。在资源竞争不激烈的情形下,性能稍微比synchronized差点点。但是当同步非常激烈的时候,synchronized的性能一下子能下降好几十倍。而ReentrantLock还能保证正常的性能。

且这个锁可以定义成公平锁还可以定义成非公平锁。

  /**
   * ReentrantLock用id
   */
  private static volatile Long lockId=0L;

  /**
   * ReentrantLock公平锁
   */
  private static final ReentrantLock reentrantLock = new ReentrantLock(true);


  /**
   * ReentrantLock方式获取id
   * @return
   */
  public static Long getLockId(){
    reentrantLock.lock();
    try {
      lockId++;
      return lockId;
    }catch (Exception e){
      e.printStackTrace();
      return getLockId();
    }finally {
      reentrantLock.unlock();
    }
  }

我这里以公平锁作为演示对象。ReentrantLock还可以查看锁的状态, 锁是否被锁上了.
可以查看当前有多少线程再等待锁。但是因为ReentrantLock是悲观锁,加锁时会对资源进行加锁,当读取频繁时性能会不如CAS的乐观锁。所以读取频繁使用乐观锁,写入频繁使用悲观锁。

Atomic或者Concurrent使用场景:

和上面的类似,不激烈情况下,性能比synchronized略逊,而激烈的时候,也能维持常态。激烈的时候,Atomic的性能会优于ReentrantLock一倍左右。但是其有一个缺点,就是只能同步一个值,一段代码中只能出现一个Atomic的变量,多于一个同步无效。因为他不能在多个Atomic之间同步。

  /**
   * Atomic用id
   */
  private static volatile AtomicLong atomicId=new AtomicLong(0L);

  /**
   * Atomic方式获取id
   * @return
   */
  public static Long getAtomicId(){
    return atomicId.addAndGet(1);
  }

对于其他类型的比如和Map和Set可以使用用并发包下的ConcurrentHashMap和ConcurrentHashSet等线程安全的数据类型。

  /**
   * 线程安全的hashMap
   */
  private static ConcurrentHashMap<String,String> hashMap = new ConcurrentHashMap<>();
  
  public static void put(String key,String value){
    hashMap.put(key,value);
  }

  public static String get(String key{
    return hashMap.get(key);
  }

ConcurrentHashMap内部的实现是CAS的乐观锁,当锁无法取得会开始自旋,直到下一次取得锁。

到此这篇关于Java线程安全解决方案(synchronized,ReentrantLock,Atomic)的文章就介绍到这了,更多相关Java线程安全内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家! 

相关文章

  • Java OpenCV图像处理之SIFT角点检测详解

    Java OpenCV图像处理之SIFT角点检测详解

    SIFT,即尺度不变特征变换,是用于图像处理领域的一种描述。这种描述具有尺度不变性,可在图像中检测出关键点,是一种局部特征描述子。本文将详细介绍一下Java OpenCV图像处理中的SIFT角点检测,需要的可以参考一下
    2022-02-02
  • SpringBoot拦截器的配置使用介绍

    SpringBoot拦截器的配置使用介绍

    拦截器可以用来实现未满足某些条件,不容许访问某些资源。SpringBoot 支持拦截器,本文主要介绍拦截器的使用与原理
    2022-10-10
  • Java如何自定义线程池中队列

    Java如何自定义线程池中队列

    这篇文章主要介绍了Java如何自定义线程池中队列,文章围绕主题展开详细的内容介绍,具有一定的参考价值,需要的小伙伴可以参考一下
    2022-07-07
  • Java如何解决发送Post请求报Stream closed问题

    Java如何解决发送Post请求报Stream closed问题

    这篇文章主要介绍了Java如何解决发送Post请求报Stream closed问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-06-06
  • MyBatis-Plus通过插件将数据库表生成Entiry,Mapper.xml,Mapper.class的方式

    MyBatis-Plus通过插件将数据库表生成Entiry,Mapper.xml,Mapper.class的方式

    今天小编就为大家分享一篇关于MyBatis-Plus通过插件将数据库表生成Entiry,Mapper.xml,Mapper.class的方式,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2019-02-02
  • java使用链表实现约瑟夫环

    java使用链表实现约瑟夫环

    这篇文章主要为大家详细介绍了java使用链表实现约瑟夫环,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-05-05
  • 你一定不知道的Java Unsafe用法详解

    你一定不知道的Java Unsafe用法详解

    Unsafe是位于sun.misc包下的一个类,主要提供一些用于执行低级别、不安全操作的方法,如直接访问系统内存资源、自主管理内存资源等,下面这篇文章主要给大家介绍了关于Java Unsafe用法的相关资料,需要的朋友可以参考下
    2021-10-10
  • 深入浅出Java中的字节流和字符流详解

    深入浅出Java中的字节流和字符流详解

    Java 中的输入输出(I/O)流主要分为字节流和字符流,这两类流为开发者提供了高效的文件读写方式,也解决了不同编码格式下的字符处理问题,本文将带你深入了解字节流和字符流的区别、应用场景以及如何使用它们处理文件操作
    2024-12-12
  • spring之Bean的生命周期详解

    spring之Bean的生命周期详解

    本篇文章主要介绍了spring之Bean的生命周期详解,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-05-05
  • zookeeper的watch机制原理解析

    zookeeper的watch机制原理解析

    Watcher,异步通知客户端,并且删除哈希表中对应的 Key-Value,这篇文章主要介绍了zookeeper的watch机制详细讲解,需要的朋友可以参考下
    2022-06-06

最新评论