Java线程安全解决方案(synchronized,ReentrantLock,Atomic)
作者:雨developer 发布时间:2022-06-13 12:51:09
线程安全解决方案
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的乐观锁,当锁无法取得会开始自旋,直到下一次取得锁。
来源:https://blog.csdn.net/qq_42271561/article/details/108809073


猜你喜欢
- 一、编辑框EditText编辑框用于接收键盘输入的文字,由文本视图派生而来,除了TextView已有的各种属性和方法,EditText还支持
- 具体代码如下所示:import java.util.ArrayList;import java.util.List;import java.
- 首先,通过一张最新(2021.11)的编程语言排名图来了解常见的编程语言:从图中可以看出,C++的排名相对于Python、Java、C来说并
- git忽略的原理:git设置本地忽略必须保证git的远程仓库分支上没有这个要忽略的文件,如果远程分支上存在这个文件,本地在设置ignore
- 1.Java连接redisredis支持哪些语言可以操作 (去redis官网查询)1.1 使用Jedis (1)添加jedis依赖
- 一、同步问题提出线程的同步是为了防止多个线程访问一个数据对象时,对数据造成的破坏。例如:两个线程ThreadA、ThreadB都操作同一个对
- 二叉排序树,又称为二叉查找树。它或者是一颗空树,或者是具有下列性质的二叉树:若它的左子树不为空。则左子树上所有的结点的值均小于跟的结点值若它
- Android 处理OnItemClickListener时关于焦点颜色的设置问题  
- Android通过wifi连接手机的方法,供大家参考,具体内容如下1.首先电脑,手机连接同一个网络2.在Android studio中Ter
- 一 数据库操作框架的历程1.1 JDBCJDBC(Java Data Base Connection,java数据库连接)是一种用于执行SQ
- Android自定义实现图片加文字功能分四步来写: 1,组合控件的xml; 2,自定义组合控件的属性; 3,自定义继承组合布局的class类
- 一、遇到一个问题1、读取CSV文件package com.guor.demo.charset;import java.io.Buffered
- 谨记:Url表只储存受保护的资源,不在表里的资源说明不受保护,任何人都可以访问1、MyFilterInvocationSecurityMet
- 一个应用场景,浏览器上传一个文件,此文件后台调用文件转换,需要耗费相当长的时间,这样,如果是一个线程同步式的做下去,那么用户在浏览器上感觉就
- 前言在上一篇普通的加载千篇一律,有趣的 loading 万里挑一 中,我们介绍了使用Path类的PathMetrics属性来控制绘制点在路径
- 上一篇讲完注解,这篇咱们科普一 * 解的其中一种用途——注解处理器(APT),文章会手把手的帮助大家学
- 一、基本定义Arrays类,全路径java.util.Arrays,主要功能为操作数组,Arrays类的所有方法均为静态方法,所以调用方式全
- 本文实例讲述了JAVA中的final关键字用法。分享给大家供大家参考,具体如下:根据上下文环境,java的关键字final也存在着细微的区别
- 一、前言字符串是多个字符连接起来组合成的字符序列。字符串分为可变的字符串和不可变的字符串两种。(1)不可变的字符串:当字符串对象创建完毕之后
- 本文以实例形式讲述了C#命令模式的实现方法,分享给大家供大家参考。具体实现方法如下:现假设想让遥控器控制电灯的开关、电视机的开关和切换,该如